From 683c3ddaa5191625ea99cd463d4d7d42c033b461 Mon Sep 17 00:00:00 2001 From: darksun Date: Fri, 30 Nov 2018 23:33:58 +0800 Subject: [PATCH 01/12] =?UTF-8?q?=E9=80=89=E9=A2=98:=20An=20introduction?= =?UTF-8?q?=20to=20the=20Pyramid=20web=20framework=20for=20Python?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...to the Pyramid web framework for Python.md | 617 ++++++++++++++++++ 1 file changed, 617 insertions(+) create mode 100644 sources/tech/20180514 An introduction to the Pyramid web framework for Python.md diff --git a/sources/tech/20180514 An introduction to the Pyramid web framework for Python.md b/sources/tech/20180514 An introduction to the Pyramid web framework for Python.md new file mode 100644 index 0000000000..a16e604774 --- /dev/null +++ b/sources/tech/20180514 An introduction to the Pyramid web framework for Python.md @@ -0,0 +1,617 @@ +[#]: collector: (lujun9972) +[#]: translator: ( ) +[#]: reviewer: ( ) +[#]: publisher: ( ) +[#]: subject: (An introduction to the Pyramid web framework for Python) +[#]: via: (https://opensource.com/article/18/5/pyramid-framework) +[#]: author: (Nicholas Hunt-Walker https://opensource.com/users/nhuntwalker) +[#]: url: ( ) + +An introduction to the Pyramid web framework for Python +====== +In the second part in a series comparing Python frameworks, learn about Pyramid. +![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/pyramid.png?itok=hX73LWtl) + +In the [first article][1] in this four-part series comparing different Python web frameworks, I explained how to create a To-Do List web application in the [Flask][2] web framework. In this second article, I'll do the same task with the [Pyramid][3] web framework. Future articles will look at [Tornado][4] and [Django][5]; as I go along, I'll explore more of the differences among them. + +### Installing, starting up, and doing configuration + +Self-described as "the start small, finish big, stay finished framework," Pyramid is much like Flask in that it takes very little effort to get it up and running. In fact, you'll recognize many of the same patterns as you build out this application. The major difference between the two, however, is that Pyramid comes with several useful utilities, which I'll describe shortly. + +To get started, create a virtual environment and install the package. + +``` +$ mkdir pyramid_todo +$ cd pyramid_todo +$ pipenv install --python 3.6 +$ pipenv shell +(pyramid-someHash) $ pipenv install pyramid +``` + +As with Flask, it's smart to create a `setup.py` file to make the app you build an easily installable Python distribution. + +``` +# setup.py +from setuptools import setup, find_packages + +requires = [ +    'pyramid', +    'paster_pastedeploy', +    'pyramid-ipython', +    'waitress' +] + +setup( +    name='pyramid_todo', +    version='0.0', +    description='A To-Do List build with Pyramid', +    author='', +    author_email='', +    keywords='web pyramid pylons', +    packages=find_packages(), +    include_package_data=True, +    install_requires=requires, +    entry_points={ +        'paste.app_factory': [ +            'main = todo:main', +        ] +    } +) +``` + +`entry_points` section near the end sets up entry points into the application that other services can use. This allows the `plaster_pastedeploy` package to access what will be the `main` function in the application for building an application object and serving it. (I'll circle back to this in a bit.) + +Thesection near the end sets up entry points into the application that other services can use. This allows thepackage to access what will be thefunction in the application for building an application object and serving it. (I'll circle back to this in a bit.) + +When you installed `pyramid`, you also gained a few Pyramid-specific shell commands; the main ones to pay attention to are `pserve` and `pshell`. `pserve` will take an INI-style configuration file specified as an argument and serve the application locally. `pshell` will also take a configuration file as an argument, but instead of serving the application, it'll open up a Python shell that is aware of the application and its internal configuration. + +The configuration file is pretty important, so it's worth a closer look. Pyramid can take its configuration from environment variables or a configuration file. To avoid too much confusion around what is where, in this tutorial you'll write most of your configuration in the configuration file, with only a select few, sensitive configuration parameters set in the virtual environment. + +Create a file called `config.ini` + +``` +[app:main] +use = egg:todo +pyramid.default_locale_name = en + +[server:main] +use = egg:waitress#main +listen = localhost:6543 +``` + +This says a couple of things: + + * The actual application will come from the `main` function located in the `todo` package installed in the environment + * To serve this app, use the `waitress` package installed in the environment and serve on localhost port 6543 + + + +When serving an application and working in development, it helps to set up logging so you can see what's going on. The following configuration will handle logging for the application: + +``` +# continuing on... +[loggers] +keys = root, todo + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = INFO +handlers = console + +[logger_todo] +level = DEBUG +handlers = +qualname = todo + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic + +[formatter_generic] +format = %(asctime)s %(levelname)-5.5s [%(name)s:%(lineno)s][%(threadName)s] %(message)s +``` + +In short, this configuration asks to log everything to do with the application to the console. If you want less output, set the logging level to `WARN` so a message will fire only if there's a problem. + +Because Pyramid is meant for an application that grows, plan out a file structure that could support that growth. Web applications can, of course, be built however you want. In general, the conceptual blocks you'll want to cover will contain: + + * **Models** for containing the code and logic for dealing with data representations + * **Views** for code and logic pertaining to the request-response cycle + * **Routes** for the paths for access to the functionality of your application + * **Scripts** for any code that might be used in configuration or management of the application itself + + + +Given the above, the file structure can look like so: + +``` +setup.py +config.ini +todo/ +    __init__.py +    models.py +    routes.py +    views.py +    scripts/ +``` + +Much like Flask's `app` object, Pyramid has its own central configuration. It comes from its `config` module and is known as the `Configurator` object. This object will handle everything from route configuration to pointing to where models and views exist. All this is done in an inner directory called `todo` within an `__init__.py` file. + +``` +# todo/__init__.py + +from pyramid.config import Configurator + +def main(global_config, **settings): +    """Returns a Pyramid WSGI application.""" +    config = Configurator(settings=settings) +    config.scan() +    return config.make_wsgi_app() +``` + +The `main` function looks for some global configuration from your environment as well as any settings that came through the particular configuration file you provide when you run the application. It takes those settings and uses them to build an instance of the `Configurator` object, which (for all intents and purposes) is the factory for your application. Finally, `config.scan()` looks for any views you'd like to attach to your application that are marked as Pyramid views. + +Wow, that was a lot to configure. + +### Using routes and views + +Now that a chunk of the configuration is done, you can start adding functionality to the application. Functionality comes in the form of URL routes that external clients can hit, which then map to functions that Python can run. + +With Pyramid, all functionality must be added to the `Configurator` in some way, shape, or form. For example, say you want to build the same simple `hello_world` view that you built with Flask, mapping to the route of `/`. With Pyramid, you can register the `/` route with the `Configurator` using the `.add_route()` method. This method takes as arguments the name of the route that you want to add as well as the actual pattern that must be matched to access that route. For this case, add the following to your `Configurator`: + +``` +config.add_route('home', '/') +``` + +Until you create a view and attach it to that route, that path into your application sits open and alone. When you add the view, make sure to include the `request` object in the parameter list. Every Pyramid view must have the `request` object as its first parameter, as that's what's being passed as the first argument to the view when it's called by Pyramid. + +One similarity that Pyramid views share with Flask is that you can mark a function as a view with a decorator. Specifically, the `@view_config` decorator from `pyramid.view`. + +In `views.py`, build the view that you want to see in the world. + +``` +from pyramid.view import view_config + +@view_config(route_name="hello", renderer="string") +def hello_world(request): +    """Print 'Hello, world!' as the response body.""" +    return 'Hello, world!' +``` + +With the `@view_config` decorator, you have to at least specify the name of the route that will map to this particular view. You can stack `view_config` decorators on top of one another to map to multiple routes if you want, but you have to have at least one to connect view the view at all, and each one must include the name of a route. **[NOTE: Is "to connect view the view" phrased correctly?]** + +The other argument, `renderer`, is optional but not really. If you don't specify a renderer, you have to deliberately construct the HTTP response you want to send back to the client using the `Response` object from `pyramid.response`. By specifying the `renderer` as a string, Pyramid knows to take whatever is returned by this function and wrap it in that same `Response` object with the MIME type of `text/plain`. By default, Pyramid allows you to use `string` and `json` as renderers. If you've attached a templating engine to your application because you want to have Pyramid generate your HTML as well, you can point directly to your HTML template as your renderer. + +The first view is done. Here's what `__init__.py` looks like now with the attached route. + +``` +# in __init__.py +from pyramid.config import Configurator + +def main(global_config, **settings): +    """Returns a Pyramid WSGI application.""" +    config = Configurator(settings=settings) +    config.add_route('hello', '/') +    config.scan() +    return config.make_wsgi_app() +``` + +Spectacular! Getting here was no easy feat, but now that you're set up, you can add functionality with significantly less difficulty. + +### Smoothing a rough edge + +Right now the application only has one route, but it's easy to see that a large application can have many dozens or even hundreds of routes. Containing them all in the same `main` function with your central configuration isn't really the best idea, because it would become cluttered. Thankfully, it's fairly easy to include routes with a few tweaks to the application. + +**One** : In the `routes.py` file, create a function called `includeme` (yes, it must actually be named this) that takes a configurator object as an argument. + +``` +# in routes.py +def includeme(config): +    """Include these routes within the application.""" +``` + +**Two** : Move the `config.add_route` method call from `__init__.py` into the `includeme` function: + +``` +def includeme(config): +    """Include these routes within the application.""" +    config.add_route('hello', '/') +``` + +**Three** : Alert the Configurator that you need to include this `routes.py` file as part of its configuration. Because it's in the same directory as `__init__.py`, you can get away with specifying the import path to this file as `.routes`. + +``` +# in __init__.py +from pyramid.config import Configurator + +def main(global_config, **settings): +    """Returns a Pyramid WSGI application.""" +    config = Configurator(settings=settings) +    config.include('.routes') +    config.scan() +    return config.make_wsgi_app() +``` + +### Connecting the database + +As with Flask, you'll want to persist data by connecting a database. Pyramid will leverage [SQLAlchemy][6] directly instead of using a specially tailored package. + +First get the easy part out of the way. `psycopg2` and `sqlalchemy` are required to talk to the Postgres database and manage the models, so add them to `setup.py`. + +``` +# in setup.py +requires = [ +    'pyramid', +    'pyramid-ipython', +    'waitress', +    'sqlalchemy', +    'psycopg2' +] +# blah blah other code +``` + +Now, you have a decision to make about how you'll include the database's URL. There's no wrong answer here; what you do will depend on the application you're building and how public your codebase needs to be. + +The first option will keep as much configuration in one place as possible by hard-coding the database URL into the `config.ini` file. One drawback is this creates a security risk for applications with a public codebase. Anyone who can view the codebase will be able to see the full database URL, including username, password, database name, and port. Another is maintainability; if you needed to change environments or the application's database location, you'd have to modify the `config.ini` file directly. Either that or you'll have to maintain one configuration file for each new environment, which adds the potential for discontinuity and errors in the application. **If you choose this option** , modify the `config.ini` file under the `[app:main]` heading to include this key-value pair: + +``` +sqlalchemy.url = postgres://localhost:5432/pyramid_todo +``` + +The second option specifies the location of the database URL when you create the `Configurator`, pointing to an environment variable whose value can be set depending on the environment where you're working. One drawback is that you're further splintering the configuration, with some in the `config.ini` file and some directly in the Python codebase. Another drawback is that when you need to use the database URL anywhere else in the application (e.g., in a database management script), you have to code in a second reference to that same environment variable (or set up the variable in one place and import from that location). **If you choose this option** , add the following: + +``` +# in __init__.py +import os +from pyramid.config import Configurator + +SQLALCHEMY_URL = os.environ.get('DATABASE_URL', '') + +def main(global_config, **settings): +    """Returns a Pyramid WSGI application.""" +    settings['sqlalchemy.url'] = SQLALCHEMY_URL # <-- important! +    config = Configurator(settings=settings) +    config.include('.routes') +    config.scan() +    return config.make_wsgi_app() +``` + +### Defining objects + +OK, so now you have a database. Now you need `Task` and `User` objects. + +Because it uses SQLAlchemy directly, Pyramid differs somewhat from Flash on how objects are built. First, every object you want to construct must inherit from SQLAlchemy's [declarative base class][7]. It'll keep track of everything that inherits from it, enabling simpler management of the database. + +``` +# in models.py +from sqlalchemy.ext.declarative import declarative_base + +Base = declarative_base() + +class Task(Base): +    pass + +class User(Base): +    pass +``` + +The columns, data types for those columns, and model relationships will be declared in much the same way as with Flask, although they'll be imported directly from SQLAlchemy instead of some pre-constructed `db` object. Everything else is the same. + +``` +# in models.py +from datetime import datetime +import secrets + +from sqlalchemy import ( +    Column, Unicode, Integer, DateTime, Boolean, relationship +) +from sqlalchemy.ext.declarative import declarative_base + +Base = declarative_base() + +class Task(Base): +    """Tasks for the To Do list.""" +    id = Column(Integer, primary_key=True) +    name = Column(Unicode, nullable=False) +    note = Column(Unicode) +    creation_date = Column(DateTime, nullable=False) +    due_date = Column(DateTime) +    completed = Column(Boolean, default=False) +    user_id = Column(Integer, ForeignKey('user.id'), nullable=False) +    user = relationship("user", back_populates="tasks") + +    def __init__(self, *args, **kwargs): +        """On construction, set date of creation.""" +        super().__init__(*args, **kwargs) +        self.creation_date = datetime.now() + +class User(Base): +    """The User object that owns tasks.""" +    id = Column(Integer, primary_key=True) +    username = Column(Unicode, nullable=False) +    email = Column(Unicode, nullable=False) +    password = Column(Unicode, nullable=False) +    date_joined = Column(DateTime, nullable=False) +    token = Column(Unicode, nullable=False) +    tasks = relationship("Task", back_populates="user") + +    def __init__(self, *args, **kwargs): +        """On construction, set date of creation.""" +        super().__init__(*args, **kwargs) +        self.date_joined = datetime.now() +        self.token = secrets.token_urlsafe(64) +``` + +Note that there's no `config.include` line for `models.py` anywhere because it's not needed. A `config.include` line is needed only if some part of the application's configuration needs to be changed. This has only created two objects, inheriting from some `Base` class that SQLAlchemy gave us. + +### Initializing the database + +Now that the models are done, you can write a script to talk to and initialize the database. In the `scripts` directory, create two files: `__init__.py` and `initializedb.py`. The first is simply to turn the `scripts` directory into a Python package. The second is the script needed for database management. + +`initializedb.py` needs a function to set up the necessary tables in the database. Like with Flask, this script must be aware of the `Base` object, whose metadata keeps track of every class that inherits from it. The database URL is required to point to and modify its tables. + +As such, this database initialization script will work: + +``` +# initializedb.py +from sqlalchemy import engine_from_config +from todo import SQLALCHEMY_URL +from todo.models import Base + +def main(): +    settings = {'sqlalchemy.url': SQLALCHEMY_URL} +    engine = engine_from_config(settings, prefix='sqlalchemy.') +    if bool(os.environ.get('DEBUG', '')): +        Base.metadata.drop_all(engine) +    Base.metadata.create_all(engine) +``` + +**Important note:** This will work only if you include the database URL as an environment variable in `todo/__init__.py` (the second option above). If the database URL was stored in the configuration file, you'll have to include a few lines to read that file. It will look something like this: + +``` +# alternate initializedb.py +from pyramid.paster import get_appsettings +from pyramid.scripts.common import parse_vars +from sqlalchemy import engine_from_config +import sys +from todo.models import Base + +def main(): +    config_uri = sys.argv[1] +    options = parse_vars(sys.argv[2:]) +    settings = get_appsettings(config_uri, options=options) +    engine = engine_from_config(settings, prefix='sqlalchemy.') +    if bool(os.environ.get('DEBUG', '')): +        Base.metadata.drop_all(engine) +    Base.metadata.create_all(engine) +``` + +Either way, in `setup.py`, add a console script that will access and run this function. + +``` +# bottom of setup.py +setup( +    # ... other stuff +    entry_points={ +        'paste.app_factory': [ +            'main = todo:main', +        ], +        'console_scripts': [ +            'initdb = todo.scripts.initializedb:main', +        ], +    } +) +``` + +When this package is installed, you'll have access to a new console script called `initdb`, which will construct the tables in your database. If the database URL is stored in the configuration file, you'll have to include the path to that file when you invoke the command. It'll look like `$ initdb /path/to/config.ini`. + +### Handling requests and the database + +Ok, here's where it gets a little deep. Let's talk about **transactions**. A "transaction," in an abstract sense, is any change made to an existing database. As with Flask, transactions are persisted no sooner than when they are committed. If changes have been made that haven't yet been committed, and you don't want those to occur (maybe there's an error thrown in the process), you can **rollback** a transaction and abort those changes. + +In Python, the [transaction package][8] allows you to interact with transactions as objects, which can roll together multiple changes into one single commit. `transaction` provides **transaction managers** , which give applications a straightforward, thread-aware way of handling transactions so all you need to think about is what to change. The `pyramid_tm` package will take the transaction manager from `transaction` and wire it up in a way that's appropriate for Pyramid's request-response cycle, attaching a transaction manager to every incoming request. + +Normally, with Pyramid the `request` object is populated when the route mapping to a view is accessed and the view function is called. Every view function will have a `request` object to work with**.** However, Pyramid allows you to modify its configuration to add whatever you might need to the `request` object. You can use the transaction manager that you'll be adding to the `request` to create a session with every request and add that session to the request. + +Yay, so why is this important? + +By attaching a transaction-managed session to the `request` object, when the view finishes processing the request, any changes made to the database session will be committed without you needing to explicitly commit**.** Here's what all these concepts look like in code. + +``` +# __init__.py +import os +from pyramid.config import Configurator +from sqlalchemy import engine_from_config +from sqlalchemy.orm import sessionmaker +import zope.sqlalchemy + +SQLALCHEMY_URL = os.environ.get('DATABASE_URL', '') + +def get_session_factory(engine): +    """Return a generator of database session objects.""" +    factory = sessionmaker() +    factory.configure(bind=engine) +    return factory + +def get_tm_session(session_factory, transaction_manager): +    """Build a session and register it as a transaction-managed session.""" +    dbsession = session_factory() +    zope.sqlalchemy.register(dbsession, transaction_manager=transaction_manager) +    return dbsession + +def main(global_config, **settings): +    """Returns a Pyramid WSGI application.""" +    settings['sqlalchemy.url'] = SQLALCHEMY_URL +    settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager' +    config = Configurator(settings=settings) +    config.include('.routes') +    config.include('pyramid_tm') +    session_factory = get_session_factory(engine_from_config(settings, prefix='sqlalchemy.')) +    config.registry['dbsession_factory'] = session_factory +    config.add_request_method( +        lambda request: get_tm_session(session_factory, request.tm), +        'dbsession', +        reify=True +    ) + +    config.scan() +    return config.make_wsgi_app() +``` + +That looks like a lot, but it only did was what was explained above, plus it added an attribute to the `request` object called `request.dbsession`. + +A few new packages were included here, so update `setup.py` with those packages. + +``` +# in setup.py +requires = [ +    'pyramid', +    'pyramid-ipython', +    'waitress', +    'sqlalchemy', +    'psycopg2', +    'pyramid_tm', +    'transaction', +    'zope.sqlalchemy' +] +# blah blah other stuff +``` + +### Revisiting routes and views + +You need to make some real views that handle the data within the database and the routes that map to them. + +Start with the routes. You created the `routes.py` file to handle your routes but didn't do much beyond the basic `/` route. Let's fix that. + +``` +# routes.py +def includeme(config): +    config.add_route('info', '/api/v1/') +    config.add_route('register', '/api/v1/accounts') +    config.add_route('profile_detail', '/api/v1/accounts/{username}') +    config.add_route('login', '/api/v1/accounts/login') +    config.add_route('logout', '/api/v1/accounts/logout') +    config.add_route('tasks', '/api/v1/accounts/{username}/tasks') +    config.add_route('task_detail', '/api/v1/accounts/{username}/tasks/{id}') +``` + +Now, it not only has static URLs like `/api/v1/accounts`, but it can handle some variable URLs like `/api/v1/accounts/{username}/tasks/{id}` where any variable in a URL will be surrounded by curly braces. + +To create the view to create an individual task in your application (like in the Flash example), you can use the `@view_config` decorator to ensure that it only takes incoming `POST` requests and check out how Pyramid handles data from the client. + +Take a look at the code, then check out how it differs from Flask's version. + +``` +# in views.py +from datetime import datetime +from pyramid.view import view_config +from todo.models import Task, User + +INCOMING_DATE_FMT = '%d/%m/%Y %H:%M:%S' + +@view_config(route_name="tasks", request_method="POST", renderer='json') +def create_task(request): +    """Create a task for one user.""" +    response = request.response +    response.headers.extend({'Content-Type': 'application/json'}) +    user = request.dbsession.query(User).filter_by(username=request.matchdict['username']).first() +    if user: +        due_date = request.json['due_date'] +        task = Task( +            name=request.json['name'], +            note=request.json['note'], +            due_date=datetime.strptime(due_date, INCOMING_DATE_FMT) if due_date else None, +            completed=bool(request.json['completed']), +            user_id=user.id +        ) +        request.dbsession.add(task) +        response.status_code = 201 +        return {'msg': 'posted'} +``` + +To start, note on the `@view_config` decorator that the only type of request you want this view to handle is a "POST" request. If you want to specify one type of request or one set of requests, provide either the string noting the request or a tuple/list of such strings. + +``` +response = request.response +response.headers.extend({'Content-Type': 'application/json'}) +# ...other code... +response.status_code = 201 +``` + +The HTTP response sent to the client is generated based on `request.response`. Normally, you wouldn't have to worry about that object. It would just produce a properly formatted HTTP response and you'd never know the difference. However, because you want to do something specific, like modify the response's status code and headers, you need to access that response and its methods/attributes. + +Unlike with Flask, you don't need to modify the view function parameter list just because you have variables in the route URL. Instead, any time a variable exists in the route URL, it is collected in the `matchdict` attribute of the `request`. It will exist there as a key-value pair, where the key will be the variable (e.g., "username") and the value will be whatever value was specified in the route (e.g., "bobdobson"). Regardless of what value is passed in through the route URL, it'll always show up as a string in the `matchdict`. So, when you want to pull the username from the incoming request URL, access it with `request.matchdict['username']` + +``` +user = request.dbsession.query(User).filter_by(username=request.matchdict['username']).first() +``` + +Querying for objects when using `sqlalchemy` directly differs significantly from what the `flask-sqlalchemy` package allows. Recall that when you used `flask-sqlalchemy` to build your models, the models inherited from the `db.Model` object. That `db` object already contained a connection to the database, so that connection could perform a straightforward operation like `User.query.all()`. + +That simple interface isn't present here, as the models in the Pyramid app inherit from `Base`, which is generated from `declarative_base()`, coming directly from the `sqlalchemy` package. It has no direct awareness of the database it'll be accessing. That awareness was attached to the `request` object via the app's central configuration as the `dbsession` attribute. Here's the code from above that did that: + +``` +config.add_request_method( +    lambda request: get_tm_session(session_factory, request.tm), +    'dbsession', +    reify=True +) +``` + +With all that said, whenever you want to query OR modify the database, you must work through `request.dbsession`. In the case, you want to query your "users" table for a specific user by using their username as their identifier. As such, the `User` object is provided as an argument to the `.query` method, then the normal SQLAlchemy operations are done from there. + +An interesting thing about this way of querying the database is that you can query for more than just one object or list of one type of object. You can query for: + + * Object attributes on their own, e.g., `request.dbsession.query(User.username)` would query for usernames + * Tuples of object attributes, e.g., `request.dbsession.query(User.username, User.date_joined)` + * Tuples of multiple objects, e.g., `request.dbsession.query(User, Task)` + + + +The data sent along with the incoming request will be found within the `request.json` dictionary. + +The last major difference is, because of all the machinations necessary to attach the committing of a session's activity to Pyramid's request-response cycle, you don't have to call `request.dbsession.commit()` at the end of your view. It's convenient, but there is one thing to be aware of moving forward. If instead of a new add to the database, you wanted to edit a pre-existing object in the database, you couldn't use `request.dbsession.commit()`. Pyramid will throw an error, saying something along the lines of "commit behavior is being handled by the transaction manager, so you can't call it on your own." And if you don't do something that resembles committing your changes, your changes won't stick. + +The solution here is to use `request.dbsession.flush()`. The job of `.flush()` is to signal to the database that some changes have been made and need to be included with the next commit. + +### Planning for the future + +At this point, you've set up most of the important parts of Pyramid, analogous to what you constructed with Flask in part one. There's much more that goes into an application, but much of the meat is handled here. Other view functions will follow similar formatting, and of course, there's always the question of security (which Pyramid has built in!). + +One of the major differences I see in the setup of a Pyramid application is that it has a much more intense configuration step than there is with Flask. I broke down those configuration steps to explain more about what's going on when a Pyramid application is constructed. However, it'd be disingenuous to act like I've known all of this since I started programming. My first experience with the Pyramid framework was with Pyramid 1.7 and its scaffolding system of `pcreate`, which builds out most of the necessary configuration, so all you need to do is think about the functionality you want to build. + +As of Pyramid 1.8, `pcreate` has been deprecated in favor of [cookiecutter][9], which effectively does the same thing. The difference is that it's maintained by someone else, and there are cookiecutter templates for more than just Pyramid projects. Now that we've gone through the components of a Pyramid project, I'd never endorse building a Pyramid project from scratch again when a cookiecutter template is available. Why do the hard work if you don't have to? In fact, the [pyramid-cookiecutter-alchemy][10] template would accomplish much of what I've written here (and a little bit more). It's actually similar to the `pcreate` scaffold I used when I first learned Pyramid. + +Learn more Python at [PyCon Cleveland 2018][11]. + +-------------------------------------------------------------------------------- + +via: https://opensource.com/article/18/5/pyramid-framework + +作者:[Nicholas Hunt-Walker][a] +选题:[lujun9972][b] +译者:[译者ID](https://github.com/译者ID) +校对:[校对者ID](https://github.com/校对者ID) + +本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出 + +[a]: https://opensource.com/users/nhuntwalker +[b]: https://github.com/lujun9972 +[1]: https://opensource.com/article/18/4/flask +[2]: http://flask.pocoo.org/ +[3]: https://trypyramid.com/ +[4]: http://www.tornadoweb.org/en/stable/ +[5]: https://www.djangoproject.com/ +[6]: https://www.sqlalchemy.org/ +[7]: http://docs.sqlalchemy.org/en/latest/orm/extensions/declarative/api.html#api-reference +[8]: http://zodb.readthedocs.io/en/latest/transactions.html +[9]: https://cookiecutter.readthedocs.io/en/latest/ +[10]: https://github.com/Pylons/pyramid-cookiecutter-alchemy +[11]: https://us.pycon.org/2018/ From fb1db41591ea0d4fbc20078d55b3da841574ad2e Mon Sep 17 00:00:00 2001 From: darksun Date: Fri, 30 Nov 2018 23:34:13 +0800 Subject: [PATCH 02/12] add done: 20180514 An introduction to the Pyramid web framework for Python.md --- build/status/status.json | 2121 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 2121 insertions(+) create mode 100644 build/status/status.json diff --git a/build/status/status.json b/build/status/status.json new file mode 100644 index 0000000000..da99c7d874 --- /dev/null +++ b/build/status/status.json @@ -0,0 +1,2121 @@ +{ + "translating": [ + { + "file": "sources/talk/20180904 Why schools of the future are open.md", + "time": "2018-11-06", + "user": "hkurj" + }, + { + "file": "sources/talk/20170921 The Rise and Rise of JSON.md", + "time": "2018-11-02", + "user": "thecyanbird" + }, + { + "file": "sources/talk/20180412 A new approach to security instrumentation.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20181029 How I organize my knowledge as a Software Engineer.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20181116 Akash Angle- How do you Fedora.md", + "time": "2018-11-22", + "user": "geekpi" + }, + { + "file": "sources/tech/20180523 How to dual-boot Linux and Windows.md", + "time": "2018-11-08", + "user": "Auk7F7" + }, + { + "file": "sources/tech/20171108 Continuous infrastructure- The other CI.md", + "time": "2018-11-24", + "user": "Jamkr" + }, + { + "file": "sources/tech/20180725 Build an interactive CLI with Node.js.md", + "time": "2018-10-29", + "user": "chenliang" + }, + { + "file": "sources/tech/20180727 How to analyze your system with perf and Python.md", + "time": "2018-11-03", + "user": "erlinux" + }, + { + "file": "sources/tech/20180417 How To Browse Stack Overflow From Terminal.md", + "time": "2018-11-21", + "user": "geekpi" + }, + { + "file": "sources/tech/20180806 GPaste Is A Great Clipboard Manager For Gnome Shell.md", + "time": "2018-11-23", + "user": "geekpi" + }, + { + "file": "sources/tech/20180131 For your first HTML code lets help Batman write a love letter.md", + "time": "2018-11-07", + "user": "MjSeven" + }, + { + "file": "sources/tech/20181004 4 Must-Have Tools for Monitoring Linux.md", + "time": "2018-11-02", + "user": "way-ww" + }, + { + "file": "sources/tech/20181105 How to manage storage on Linux with LVM.md", + "time": "2018-11-20", + "user": "ziang" + }, + { + "file": "sources/tech/20180707 Version Control Before Git with CVS.md", + "time": "2018-11-19", + "user": "runningwater" + }, + { + "file": "sources/tech/20181008 Taking notes with Laverna, a web-based information organizer.md", + "time": "2018-10-30", + "user": "ChenYi" + }, + { + "file": "sources/tech/20181011 Exploring the Linux kernel- The secrets of Kconfig-kbuild.md", + "time": "2018-10-27", + "user": "leemeans" + }, + { + "file": "sources/tech/20171202 Easily control delivery of your Python applications to millions of Linux users with Snapcraft.md", + "time": "2018-10-30", + "user": "David Chen" + }, + { + "file": "sources/tech/20181102 Create a containerized machine learning model.md", + "time": "2018-11-07", + "user": "suncle" + }, + { + "file": "sources/tech/20181119 9 obscure Python libraries for data science.md", + "time": "2018-11-23", + "user": "heguangzhi" + }, + { + "file": "sources/tech/20181115 3 best practices for continuous integration and deployment.md", + "time": "2018-11-19", + "user": "Leon Chi" + }, + { + "file": "sources/tech/20181120 How To Change GDM Login Screen Background In Ubuntu.md", + "time": "2018-11-23", + "user": "guevaraya" + } + ], + "unselected": [ + { + "file": "sources/talk/20170908 Betting on the Web.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20170911 What every software engineer should know about search.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20180109 How Mycroft used WordPress and GitHub to improve its documentation.md", + "time": "2018-01-11", + "user": "darksun" + }, + { + "file": "sources/talk/20181003 13 tools to measure DevOps success.md", + "time": "2018-10-08", + "user": "darksun" + }, + { + "file": "sources/talk/20180719 Finding Jobs in Software.md", + "time": "2018-11-20", + "user": "darksun" + }, + { + "file": "sources/talk/20180124 Security Chaos Engineering- A new paradigm for cybersecurity.md", + "time": "2018-01-26", + "user": "darksun" + }, + { + "file": "sources/talk/20171119 The Ruby Story.md", + "time": "2018-10-25", + "user": "darksun" + }, + { + "file": "sources/talk/20180201 6 pivotal moments in open source history.md", + "time": "2018-02-04", + "user": "Ezio" + }, + { + "file": "sources/talk/20180206 Building Slack for the Linux community and adopting snaps.md", + "time": "2018-02-08", + "user": "darksun" + }, + { + "file": "sources/talk/20180206 UQDS- A software-development process that puts quality first.md", + "time": "2018-02-08", + "user": "darksun" + }, + { + "file": "sources/talk/20180207 Why Mainframes Aren-t Going Away Any Time Soon.md", + "time": "2018-02-09", + "user": "darksun" + }, + { + "file": "sources/talk/20180208 Gathering project requirements using the Open Decision Framework.md", + "time": "2018-02-11", + "user": "darksun" + }, + { + "file": "sources/talk/20180209 Arch Anywhere Is Dead, Long Live Anarchy Linux.md", + "time": "2018-02-11", + "user": "darksun" + }, + { + "file": "sources/talk/20180209 How writing can change your career for the better, even if you don-t identify as a writer.md", + "time": "2018-10-24", + "user": "lctt-bot" + }, + { + "file": "sources/talk/20180209 Why an involved user community makes for better software.md", + "time": "2018-02-12", + "user": "darksun" + }, + { + "file": "sources/talk/20180214 Can anonymity and accountability coexist.md", + "time": "2018-02-14", + "user": "DarkSun" + }, + { + "file": "sources/talk/20180220 4 considerations when naming software development projects.md", + "time": "2018-02-24", + "user": "darksun" + }, + { + "file": "sources/talk/20180221 3 warning flags of DevOps metrics.md", + "time": "2018-03-06", + "user": "darksun" + }, + { + "file": "sources/talk/20180222 3 reasons to say -no- in DevOps.md", + "time": "2018-02-22", + "user": "darksun" + }, + { + "file": "sources/talk/20180223 Why culture is the most important issue in a DevOps transformation.md", + "time": "2018-03-01", + "user": "darksun" + }, + { + "file": "sources/talk/20180227 Emacs -1- Ditching a bunch of stuff and moving to Emacs and org-mode.md", + "time": "2018-03-01", + "user": "darksun" + }, + { + "file": "sources/talk/20180301 How to hire the right DevOps talent.md", + "time": "2018-03-06", + "user": "darksun" + }, + { + "file": "sources/talk/20180302 Beyond metrics- How to operate as team on today-s open source project.md", + "time": "2018-03-07", + "user": "darksun" + }, + { + "file": "sources/talk/20180303 4 meetup ideas- Make your data open.md", + "time": "2018-03-07", + "user": "darksun" + }, + { + "file": "sources/talk/20180314 How to apply systems thinking in DevOps.md", + "time": "2018-03-20", + "user": "darksun" + }, + { + "file": "sources/talk/20180314 Pi Day- 12 fun facts and ways to celebrate.md", + "time": "2018-03-20", + "user": "darksun" + }, + { + "file": "sources/talk/20180315 6 ways a thriving community will help your project succeed.md", + "time": "2018-03-20", + "user": "darksun" + }, + { + "file": "sources/talk/20180315 Lessons Learned from Growing an Open Source Project Too Fast.md", + "time": "2018-06-13", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20180316 How to avoid humiliating newcomers- A guide for advanced developers.md", + "time": "2018-03-20", + "user": "darksun" + }, + { + "file": "sources/talk/20180319 6 common questions about agile development practices for teams.md", + "time": "2018-03-22", + "user": "darksun" + }, + { + "file": "sources/talk/20180321 8 tips for better agile retrospective meetings.md", + "time": "2018-03-22", + "user": "darksun" + }, + { + "file": "sources/talk/20180323 7 steps to DevOps hiring success.md", + "time": "2018-03-26", + "user": "darksun" + }, + { + "file": "sources/talk/20180117 How technology changes the rules for doing agile.md", + "time": "2018-11-11", + "user": "lctt-bot" + }, + { + "file": "sources/talk/20180330 Meet OpenAuto, an Android Auto emulator for Raspberry Pi.md", + "time": "2018-04-03", + "user": "darksun" + }, + { + "file": "sources/talk/20180404 Is the term DevSecOps necessary.md", + "time": "2018-04-09", + "user": "darksun" + }, + { + "file": "sources/talk/20180405 Rethinking -ownership- across the organization.md", + "time": "2018-04-09", + "user": "darksun" + }, + { + "file": "sources/talk/20171007 The Most Important Database You-ve Never Heard of.md", + "time": "2018-10-25", + "user": "darksun" + }, + { + "file": "sources/talk/20180410 Microservices Explained.md", + "time": "2018-09-28", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20180412 Management, from coordination to collaboration.md", + "time": "2018-04-16", + "user": "darksun" + }, + { + "file": "sources/talk/20180416 For project safety back up your people, not just your data.md", + "time": "2018-04-17", + "user": "darksun" + }, + { + "file": "sources/talk/20180417 How to develop the FOSS leaders of the future.md", + "time": "2018-04-18", + "user": "darksun" + }, + { + "file": "sources/talk/20171030 Why I love technical debt.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20180418 Is DevOps compatible with part-time community teams.md", + "time": "2018-05-31", + "user": "darksun" + }, + { + "file": "sources/talk/20180419 3 tips for organizing your open source project-s workflow on GitHub.md", + "time": "2018-09-28", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20180419 5 guiding principles you should know before you design a microservice.md", + "time": "2018-04-23", + "user": "darksun" + }, + { + "file": "sources/talk/20180420 What You Don-t Know About Linux Open Source Could Be Costing to More Than You Think.md", + "time": "2018-04-23", + "user": "darksun" + }, + { + "file": "sources/talk/20180424 There-s a Server in Every Serverless Platform.md", + "time": "2018-04-26", + "user": "darksun" + }, + { + "file": "sources/talk/20170928 The Lineage of Man.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20180504 How a university network assistant used Linux in the 90s.md", + "time": "2018-05-14", + "user": "darksun" + }, + { + "file": "sources/talk/20180508 Person with diabetes finds open source and builds her own medical device.md", + "time": "2018-05-10", + "user": "darksun" + }, + { + "file": "sources/talk/20180623 The IBM 029 Card Punch.md", + "time": "2018-10-24", + "user": "darksun" + }, + { + "file": "sources/talk/20180604 10 principles of resilience for women in tech.md", + "time": "2018-06-06", + "user": "darksun" + }, + { + "file": "sources/talk/20180128 Getting Linux Jobs.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20180613 AI Is Coming to Edge Computing Devices.md", + "time": "2018-06-19", + "user": "darksun" + }, + { + "file": "sources/talk/20180619 A summer reading list for open organization enthusiasts.md", + "time": "2018-06-21", + "user": "darksun" + }, + { + "file": "sources/talk/20180622 7 tips for promoting your project and community on Twitter.md", + "time": "2018-06-28", + "user": "darksun" + }, + { + "file": "sources/talk/20180703 What Game of Thrones can teach us about open innovation.md", + "time": "2018-07-05", + "user": "darksun" + }, + { + "file": "sources/talk/20180704 Comparing Twine and Ren-Py for creating interactive fiction.md", + "time": "2018-07-06", + "user": "darksun" + }, + { + "file": "sources/talk/20180705 New Training Options Address Demand for Blockchain Skills.md", + "time": "2018-07-06", + "user": "darksun" + }, + { + "file": "sources/talk/20180216 Q4OS Makes Linux Easy for Everyone.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20180713 What-s the difference between a fork and a distribution.md", + "time": "2018-07-16", + "user": "darksun" + }, + { + "file": "sources/talk/20180724 Open Source Certification- Preparing for the Exam.md", + "time": "2018-07-26", + "user": "darksun" + }, + { + "file": "sources/talk/20171222 10 keys to quick game development.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20180726 Tech jargon- The good, the bad, and the ugly.md", + "time": "2018-07-30", + "user": "darksun" + }, + { + "file": "sources/talk/20180731 How to be the lazy sysadmin.md", + "time": "2018-08-02", + "user": "darksun" + }, + { + "file": "sources/talk/20180802 Design thinking as a way of life.md", + "time": "2018-08-06", + "user": "darksun" + }, + { + "file": "sources/talk/20180802 How blockchain will influence open source.md", + "time": "2018-08-03", + "user": "darksun" + }, + { + "file": "sources/talk/20180807 Becoming a successful programmer in an underrepresented community.md", + "time": "2018-08-09", + "user": "darksun" + }, + { + "file": "sources/talk/20180807 Building more trustful teams in four steps.md", + "time": "2018-08-09", + "user": "darksun" + }, + { + "file": "sources/talk/20171229 Important Papers- Codd and the Relational Model.md", + "time": "2018-10-25", + "user": "darksun" + }, + { + "file": "sources/talk/20180808 3 tips for moving your team to a microservices architecture.md", + "time": "2018-08-10", + "user": "darksun" + }, + { + "file": "sources/talk/20180809 How do tools affect culture.md", + "time": "2018-08-10", + "user": "darksun" + }, + { + "file": "sources/talk/20180620 3 pitfalls everyone should avoid with hybrid multi-cloud, part 2.md", + "time": "2018-08-12", + "user": "darksun" + }, + { + "file": "sources/talk/20180717 Tips for Success with Open Source Certification.md", + "time": "2018-07-24", + "user": "darksun" + }, + { + "file": "sources/talk/20180816 Debian Turns 25- Here are Some Interesting Facts About Debian Linux.md", + "time": "2018-08-17", + "user": "darksun" + }, + { + "file": "sources/talk/20180104 How Creative Commons benefits artists and big business.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20180817 OERu makes a college education affordable.md", + "time": "2018-08-19", + "user": "darksun" + }, + { + "file": "sources/talk/20171114 Why pair writing helps improve documentation.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20140412 My Lisp Experiences and the Development of GNU Emacs.md", + "time": "2018-09-28", + "user": "zhousiyu325" + }, + { + "file": "sources/talk/20171115 Why and How to Set an Open Source Strategy.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20180826 How to Install and Use FreeDOS on VirtualBox.md", + "time": "2018-08-28", + "user": "darksun" + }, + { + "file": "sources/talk/20180511 Looking at the Lispy side of Perl.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20180904 How blockchain can complement open source.md", + "time": "2018-09-05", + "user": "darksun" + }, + { + "file": "sources/talk/20180527 Whatever Happened to the Semantic Web.md", + "time": "2018-10-25", + "user": "darksun" + }, + { + "file": "sources/talk/20180906 DevOps- The consequences of blame.md", + "time": "2018-09-10", + "user": "darksun" + }, + { + "file": "sources/talk/20180724 Why moving all your workloads to the cloud is a bad idea.md", + "time": "2018-09-28", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20181009 4 best practices for giving open source code feedback.md", + "time": "2018-10-11", + "user": "darksun" + }, + { + "file": "sources/talk/20171128 The politics of the Linux desktop.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20180917 How gaming turned me into a coder.md", + "time": "2018-09-18", + "user": "darksun" + }, + { + "file": "sources/talk/20180919 5 ways DevSecOps changes security.md", + "time": "2018-09-21", + "user": "darksun" + }, + { + "file": "sources/talk/20180112 in which the cost of structured data is reduced.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20181009 GCC- Optimizing Linux, the Internet, and Everything.md", + "time": "2018-10-11", + "user": "darksun" + }, + { + "file": "sources/talk/20180920 Building a Secure Ecosystem for Node.js.md", + "time": "2018-09-21", + "user": "darksun" + }, + { + "file": "sources/talk/20181010 Talk over text- Conversational interface design and usability.md", + "time": "2018-10-12", + "user": "darksun" + }, + { + "file": "sources/talk/20181011 How to level up your organization-s security expertise.md", + "time": "2018-10-15", + "user": "darksun" + }, + { + "file": "sources/talk/20181018 Think global- How to overcome cultural communication challenges.md", + "time": "2018-10-19", + "user": "darksun" + }, + { + "file": "sources/talk/20171107 How to Monetize an Open Source Project.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20180925 Troubleshooting Node.js Issues with llnode.md", + "time": "2018-10-09", + "user": "darksun" + }, + { + "file": "sources/talk/20171116 Why is collaboration so difficult.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20181004 Interview With Peter Ganten, CEO of Univention GmbH.md", + "time": "2018-10-09", + "user": "darksun" + }, + { + "file": "sources/talk/20181017 We already have nice things, and other reasons not to write in-house ops tools.md", + "time": "2018-10-19", + "user": "darksun" + }, + { + "file": "sources/talk/20171129 Inside AGL Familiar Open Source Components Ease Learning Curve.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20171221 Changing how we use Slack solved our transparency and silo problems.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20171222 18 Cyber-Security Trends Organizations Need to Brace for in 2018.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20180104 How allowing myself to be vulnerable made me a better leader.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20180111 The open organization and inner sourcing movements can share knowledge.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20180131 How to write a really great resume that actually gets you hired.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20180209 A review of Virtual Labs virtualization solutions for MOOCs - WebLog Pro Olivier Berger.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20180223 Plasma Mobile Could Give Life to a Mobile Linux Experience.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20180328 What NASA Has Been Doing About Open Science.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20180403 3 pitfalls everyone should avoid with hybrid multicloud.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20180620 Anatomy of a perfect pull request.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20180625 8 reasons to use the Xfce Linux desktop environment.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20180629 Reflecting on the GPLv3 license for its 11th anniversary.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20180701 How to migrate to the world of Linux from Windows.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20180705 5 Reasons Open Source Certification Matters More Than Ever.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20180706 Robolinux Lets You Easily Run Linux and Windows Without Dual Booting.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20180711 Becoming a senior developer 9 experiences you ll encounter.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20180711 Open hardware meets open science in a multi-microphone hearing aid project.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20180716 Confessions of a recovering Perl hacker.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20180720 A brief history of text-based games and open source.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20180722 Dawn of the Microcomputer- The Altair 8800.md", + "time": "2018-10-24", + "user": "darksun" + }, + { + "file": "sources/talk/20180818 What Did Ada Lovelace-s Program Actually Do.md", + "time": "2018-10-24", + "user": "darksun" + }, + { + "file": "sources/talk/20180820 Keeping patient data safe with open source tools.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20180831 3 innovative open source projects for the new school year.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20180916 The Rise and Demise of RSS.md", + "time": "2018-10-24", + "user": "darksun" + }, + { + "file": "sources/talk/20180930 A Short History of Chaosnet.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20181018 The case for open source classifiers in AI algorithms.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20181019 To BeOS or not to BeOS, that is the Haiku.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20181023 What MMORPGs can teach us about leveling up a heroic developer team.md", + "time": "2018-10-24", + "user": "darksun" + }, + { + "file": "sources/talk/20181024 5 tips for facilitators of agile meetings.md", + "time": "2018-10-25", + "user": "darksun" + }, + { + "file": "sources/talk/20181024 Why it matters that Microsoft released old versions of MS-DOS as open source.md", + "time": "2018-10-25", + "user": "darksun" + }, + { + "file": "sources/talk/20181031 3 scary sysadmin stories.md", + "time": "2018-11-01", + "user": "darksun" + }, + { + "file": "sources/talk/20181031 How open source hardware increases security.md", + "time": "2018-11-01", + "user": "darksun" + }, + { + "file": "sources/talk/20181107 5 signs you are doing continuous testing wrong - Opensource.com.md", + "time": "2018-11-13", + "user": "darksun" + }, + { + "file": "sources/talk/20181107 How open source in education creates new developers.md", + "time": "2018-11-13", + "user": "darksun" + }, + { + "file": "sources/talk/20181112 A Free Guide for Setting Your Open Source Strategy.md", + "time": "2018-11-13", + "user": "darksun" + }, + { + "file": "sources/talk/20181112 The Source History of Cat.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/talk/20181113 Have you seen these personalities in open source.md", + "time": "2018-11-15", + "user": "darksun" + }, + { + "file": "sources/talk/20181114 Analyzing the DNA of DevOps.md", + "time": "2018-11-16", + "user": "darksun" + }, + { + "file": "sources/talk/20181114 Is your startup built on open source- 9 tips for getting started.md", + "time": "2018-11-16", + "user": "darksun" + }, + { + "file": "sources/tech/20091104 Linux-Unix App For Prevention Of RSI (Repetitive Strain Injury).md", + "time": "2018-01-18", + "user": "darksun" + }, + { + "file": "sources/tech/20171111 A CEOs Guide to Emacs.md", + "time": "2018-09-28", + "user": "Xingyu.Wang" + }, + { + "file": "sources/tech/20140510 Managing Digital Files (e.g., Photographs) in Files and Folders.md", + "time": "2018-03-02", + "user": "darksun" + }, + { + "file": "sources/tech/20180902 Learning BASIC Like It-s 1983.md", + "time": "2018-10-24", + "user": "darksun" + }, + { + "file": "sources/tech/20171012 7 Best eBook Readers for Linux.md", + "time": "2018-10-27", + "user": "lctt-bot" + }, + { + "file": "sources/tech/20160922 Annoying Experiences Every Linux Gamer Never Wanted.md", + "time": "2017-12-09", + "user": "Ezio" + }, + { + "file": "sources/tech/20161106 Myths about -dev-urandom.md", + "time": "2018-02-06", + "user": "darksun" + }, + { + "file": "sources/tech/20180928 Quiet log noise with Python and machine learning.md", + "time": "2018-11-24", + "user": "lctt-bot" + }, + { + "file": "sources/tech/20170710 iWant - The Decentralized Peer To Peer File Sharing Commandline Application.md", + "time": "2018-07-13", + "user": "darksun" + }, + { + "file": "sources/tech/20171130 Excellent Business Software Alternatives For Linux.md", + "time": "2018-10-07", + "user": "lctt9972" + }, + { + "file": "sources/tech/20180130 Trying Other Go Versions.md", + "time": "2018-10-11", + "user": "lctt-bot" + }, + { + "file": "sources/tech/20111221 30 Best Sources For Linux - -BSD - Unix Documentation On the Web.md", + "time": "2018-10-08", + "user": "Xingyu.Wang" + }, + { + "file": "sources/tech/20180829 4 open source monitoring tools.md", + "time": "2018-11-14", + "user": "lctt-bot" + }, + { + "file": "sources/tech/20180612 Systemd Services- Reacting to Change.md", + "time": "2018-11-02", + "user": "darksun" + }, + { + "file": "sources/tech/20180518 How to Manage Fonts in Linux.md", + "time": "2018-09-28", + "user": "Xingyu.Wang" + }, + { + "file": "sources/tech/20180619 Systemd Services- Monitoring Files and Directories.md", + "time": "2018-11-02", + "user": "darksun" + }, + { + "file": "sources/tech/20170928 How to create a free baby monitoring system with Gonimo.md", + "time": "2018-01-06", + "user": "darksun" + }, + { + "file": "sources/tech/20180522 How to Enable Click to Minimize On Ubuntu.md", + "time": "2018-10-07", + "user": "lctt9972" + }, + { + "file": "sources/tech/20171006 7 deadly sins of documentation.md", + "time": "2018-01-06", + "user": "darksun" + }, + { + "file": "sources/tech/20171006 Create a Clean-Code App with Kotlin Coroutines and Android Architecture Components.md", + "time": "2018-06-13", + "user": "Xingyu.Wang" + }, + { + "file": "sources/tech/20171010 In Device We Trust Measure Twice Compute Once with Xen Linux TPM 2.0 and TXT.md", + "time": "2018-06-13", + "user": "Xingyu.Wang" + }, + { + "file": "sources/tech/20171018 How to create an e-book chapter template in LibreOffice Writer.md", + "time": "2018-01-07", + "user": "darksun" + }, + { + "file": "sources/tech/20171005 10 Games You Can Play on Linux with Wine.md", + "time": "2018-10-27", + "user": "付峥" + }, + { + "file": "sources/tech/20180611 12 fiction books for Linux and open source types.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/tech/20171027 Share And Upload Files To Compatible Hosting Sites Automatically.md", + "time": "2018-01-05", + "user": "darksun" + }, + { + "file": "sources/tech/20171030 5 open source alternatives to Mint and Quicken for personal finance.md", + "time": "2018-01-05", + "user": "darksun" + }, + { + "file": "sources/tech/20171216 Sysadmin 101- Troubleshooting.md", + "time": "2018-11-20", + "user": "darksun" + }, + { + "file": "sources/tech/20171113 IT disaster recovery- Sysadmins vs. natural disasters - HPE.md", + "time": "2017-12-31", + "user": "darksun" + }, + { + "file": "sources/tech/20171114 Finding Files with mlocate- Part 2.md", + "time": "2017-12-29", + "user": "darksun" + }, + { + "file": "sources/tech/20171116 Unleash Your Creativity – Linux Programs for Drawing and Image Editing.md", + "time": "2017-12-03", + "user": "qhwdw" + }, + { + "file": "sources/tech/20171117 5 open source fonts ideal for programmers.md", + "time": "2017-12-31", + "user": "darksun" + }, + { + "file": "sources/tech/20171121 Finding Files with mlocate- Part 3.md", + "time": "2018-03-04", + "user": "DarkSun" + }, + { + "file": "sources/tech/20181112 Behind the scenes with Linux containers.md", + "time": "2018-11-13", + "user": "darksun" + }, + { + "file": "sources/tech/20170410 Writing a Time Series Database from Scratch.md", + "time": "2018-10-23", + "user": "lctt-bot" + }, + { + "file": "sources/tech/20170523 Best Websites to Download Linux Games.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/tech/20180327 Protecting Code Integrity with PGP - Part 7- Protecting Online Accounts.md", + "time": "2018-11-20", + "user": "Xingyu.Wang" + }, + { + "file": "sources/tech/20171129 Interactive Workflows for Cpp with Jupyter.md", + "time": "2017-12-03", + "user": "Ezio" + }, + { + "file": "sources/tech/20171129 TLDR pages Simplified Alternative To Linux Man Pages.md", + "time": "2017-12-09", + "user": "Ezio" + }, + { + "file": "sources/tech/20171130 Tap the power of community with organized chaos.md", + "time": "2017-12-27", + "user": "darksun" + }, + { + "file": "sources/tech/20171201 Linux Distros That Serve Scientific and Medical Communities.md", + "time": "2018-04-21", + "user": "Ezio" + }, + { + "file": "sources/tech/20181029 Create animated, scalable vector graphic images with MacSVG.md", + "time": "2018-11-01", + "user": "darksun" + }, + { + "file": "sources/tech/20180531 How to Build an Amazon Echo with Raspberry Pi.md", + "time": "2018-09-28", + "user": "Xingyu.Wang" + }, + { + "file": "sources/tech/20171203 Top 20 GNOME Extensions You Should Be Using Right Now.md", + "time": "2017-12-09", + "user": "Ezio" + }, + { + "file": "sources/tech/20180925 9 Easiest Ways To Find Out Process ID (PID) In Linux.md", + "time": "2018-10-28", + "user": "lctt-bot" + }, + { + "file": "sources/tech/20181029 DF-SHOW - A Terminal File Manager Based On An Old DOS Application.md", + "time": "2018-10-30", + "user": "darksun" + }, + { + "file": "sources/tech/20171206 Getting started with Turtl, an open source alternative to Evernote.md", + "time": "2017-12-08", + "user": "darksun" + }, + { + "file": "sources/tech/20181101 Getting started with OKD on your Linux desktop.md", + "time": "2018-11-02", + "user": "darksun" + }, + { + "file": "sources/tech/20171208 GeckoLinux Brings Flexibility and Choice to openSUSE.md", + "time": "2018-01-07", + "user": "darksun" + }, + { + "file": "sources/tech/20171212 Toplip – A Very Strong File Encryption And Decryption CLI Utility.md", + "time": "2018-06-13", + "user": "Xingyu.Wang" + }, + { + "file": "sources/tech/20171215 Top 5 Linux Music Players.md", + "time": "2017-12-22", + "user": "Alex Chen" + }, + { + "file": "sources/tech/20181025 How to write your favorite R functions in Python.md", + "time": "2018-10-30", + "user": "darksun" + }, + { + "file": "sources/tech/20171222 Why the diversity and inclusion conversation must include people with disabilities.md", + "time": "2017-12-27", + "user": "darksun" + }, + { + "file": "sources/tech/20171223 My personal Email setup - Notmuch, mbsync, postfix and dovecot.md", + "time": "2017-12-27", + "user": "darksun" + }, + { + "file": "sources/tech/20171224 My first Rust macro.md", + "time": "2018-03-04", + "user": "DarkSun" + }, + { + "file": "sources/tech/20171226 Top 10 Microsoft Visio Alternatives for Linux.md", + "time": "2017-12-30", + "user": "darksun" + }, + { + "file": "sources/tech/20180101 27 open solutions to everything in education.md", + "time": "2018-01-05", + "user": "darksun" + }, + { + "file": "sources/tech/20181123 How to Build a Netboot Server, Part 1.md", + "time": "2018-11-24", + "user": "darksun" + }, + { + "file": "sources/tech/20180821 How I recorded user behaviour on my competitor-s websites.md", + "time": "2018-08-28", + "user": "darksun" + }, + { + "file": "sources/tech/20181022 Improve login security with challenge-response authentication.md", + "time": "2018-10-23", + "user": "darksun" + }, + { + "file": "sources/tech/20181030 Podman- A more secure way to run containers.md", + "time": "2018-10-31", + "user": "darksun" + }, + { + "file": "sources/tech/20180108 5 arcade-style games in your Linux repository.md", + "time": "2018-01-09", + "user": "darksun" + }, + { + "file": "sources/tech/20180108 Debbugs Versioning- Merging.md", + "time": "2018-01-11", + "user": "darksun" + }, + { + "file": "sources/tech/20180108 SuperTux- A Linux Take on Super Mario Game.md", + "time": "2018-01-09", + "user": "Ezio" + }, + { + "file": "sources/tech/20180108 You GNOME it- Windows and Apple devs get a compelling reason to turn to Linux.md", + "time": "2018-02-04", + "user": "darksun" + }, + { + "file": "sources/tech/20180109 Profiler adventures resolving symbol addresses is hard.md", + "time": "2018-03-04", + "user": "DarkSun" + }, + { + "file": "sources/tech/20181023 How to Check HP iLO Firmware Version from Linux Command Line.md", + "time": "2018-10-31", + "user": "darksun" + }, + { + "file": "sources/tech/20181031 Working with data streams on the Linux command line.md", + "time": "2018-11-01", + "user": "darksun" + }, + { + "file": "sources/tech/20180112 8 KDE Plasma Tips and Tricks to Improve Your Productivity.md", + "time": "2018-01-18", + "user": "darksun" + }, + { + "file": "sources/tech/20180114 Playing Quake 4 on Linux in 2018.md", + "time": "2018-01-15", + "user": "darksun" + }, + { + "file": "sources/tech/20180116 How To Create A Bootable Zorin OS USB Drive.md", + "time": "2018-01-18", + "user": "darksun" + }, + { + "file": "sources/tech/20180118 Rediscovering make- the power behind rules.md", + "time": "2018-06-13", + "user": "Xingyu.Wang" + }, + { + "file": "sources/tech/20180119 Two great uses for the cp command Bash shortcuts.md", + "time": "2018-06-13", + "user": "Xingyu.Wang" + }, + { + "file": "sources/tech/20180122 Ick- a continuous integration system.md", + "time": "2018-02-04", + "user": "darksun" + }, + { + "file": "sources/tech/20180126 An introduction to the Web Simple Perl module a minimalist web framework.md", + "time": "2018-02-04", + "user": "Ezio" + }, + { + "file": "sources/tech/20180129 CopperheadOS Security features installing apps and more.md", + "time": "2018-02-04", + "user": "Ezio" + }, + { + "file": "sources/tech/20181105 5 Easy Tips for Linux Web Browser Security.md", + "time": "2018-11-19", + "user": "darksun" + }, + { + "file": "sources/tech/20180129 WebSphere MQ programming in Python with Zato.md", + "time": "2018-01-31", + "user": "darksun" + }, + { + "file": "sources/tech/20180129 What Happens When You Want to Create a Special Fille with All Special Characters in Linux.md", + "time": "2018-02-04", + "user": "Ezio" + }, + { + "file": "sources/tech/20180130 An introduction to the DomTerm terminal emulator for Linux.md", + "time": "2018-02-04", + "user": "darksun" + }, + { + "file": "sources/tech/20180130 Create and manage MacOS LaunchAgents using Go.md", + "time": "2018-02-02", + "user": "Ezio" + }, + { + "file": "sources/tech/20180130 Graphics and music tools for game development.md", + "time": "2018-02-01", + "user": "darksun" + }, + { + "file": "sources/tech/20180130 Mitigating known security risks in open source libraries.md", + "time": "2018-02-02", + "user": "Ezio" + }, + { + "file": "sources/tech/20180130 Refreshing old computers with Linux.md", + "time": "2018-02-04", + "user": "Ezio" + }, + { + "file": "sources/tech/20180130 tmux - A Powerful Terminal Multiplexer For Heavy Command-Line Linux User.md", + "time": "2018-06-13", + "user": "Xingyu.Wang" + }, + { + "file": "sources/tech/20180131 How to test Webhooks when youre developing locally.md", + "time": "2018-02-02", + "user": "Ezio" + }, + { + "file": "sources/tech/20181119 7 command-line tools for writers - Opensource.com.md", + "time": "2018-11-21", + "user": "darksun" + }, + { + "file": "sources/tech/20180131 Migrating the debichem group subversion repository to Git.md", + "time": "2018-05-25", + "user": "Ezio" + }, + { + "file": "sources/tech/20181112 A Free, Secure And Cross-platform Password Manager.md", + "time": "2018-11-13", + "user": "darksun" + }, + { + "file": "sources/tech/20180823 Getting started with Sensu monitoring.md", + "time": "2018-08-28", + "user": "darksun" + }, + { + "file": "sources/tech/20180201 I Built This - Now What How to deploy a React App on a DigitalOcean Droplet.md", + "time": "2018-02-02", + "user": "Ezio" + }, + { + "file": "sources/tech/20180205 Writing eBPF tracing tools in Rust.md", + "time": "2018-10-11", + "user": "lctt-bot" + }, + { + "file": "sources/tech/20180202 CompositeAcceleration.md", + "time": "2018-02-05", + "user": "darksun" + }, + { + "file": "sources/tech/20180202 Tips for success when getting started with Ansible.md", + "time": "2018-02-05", + "user": "darksun" + }, + { + "file": "sources/tech/20180205 Getting Started with the openbox windows manager in Fedora.md", + "time": "2018-06-13", + "user": "Xingyu.Wang" + }, + { + "file": "sources/tech/20180205 Rancher - Container Management Application.md", + "time": "2018-02-06", + "user": "darksun" + }, + { + "file": "sources/tech/20180206 Power(Shell) to the people.md", + "time": "2018-02-08", + "user": "darksun" + }, + { + "file": "sources/tech/20180207 23 open source audio-visual production tools.md", + "time": "2018-02-09", + "user": "darksun" + }, + { + "file": "sources/tech/20180208 How to start writing macros in LibreOffice Basic.md", + "time": "2018-02-09", + "user": "darksun" + }, + { + "file": "sources/tech/20181114 How to use systemd-nspawn for Linux system recovery.md", + "time": "2018-11-16", + "user": "darksun" + }, + { + "file": "sources/tech/20180209 How to use Twine and SugarCube to create interactive adventure games.md", + "time": "2018-02-11", + "user": "darksun" + }, + { + "file": "sources/tech/20180211 Latching Mutations with GitOps.md", + "time": "2018-04-06", + "user": "Ezio" + }, + { + "file": "sources/tech/20181017 Automating upstream releases with release-bot.md", + "time": "2018-10-18", + "user": "darksun" + }, + { + "file": "sources/tech/20181107 Top 30 OpenStack Interview Questions and Answers.md", + "time": "2018-11-13", + "user": "darksun" + }, + { + "file": "sources/tech/20181109 Must-Have Tools for Writers on the Linux Platform.md", + "time": "2018-11-13", + "user": "darksun" + }, + { + "file": "sources/tech/20181113 An introduction to Udev- The Linux subsystem for managing device events.md", + "time": "2018-11-14", + "user": "darksun" + }, + { + "file": "sources/tech/20180225 What I learnt from building 3 high traffic web applications on an embedded key value store.md", + "time": "2018-04-06", + "user": "Ezio" + }, + { + "file": "sources/tech/20180226 -Getting to Done- on the Linux command line.md", + "time": "2018-03-01", + "user": "darksun" + }, + { + "file": "sources/tech/20180824 Add free books to your eReader- Formatting tips.md", + "time": "2018-08-28", + "user": "darksun" + }, + { + "file": "sources/tech/20180302 How to manage your workstation configuration with Ansible.md", + "time": "2018-03-05", + "user": "darksun" + }, + { + "file": "sources/tech/20180129 The 5 Best Linux Distributions for Development.md", + "time": "2018-10-25", + "user": "Xingyu.Wang" + }, + { + "file": "sources/tech/20180306 Exploring free and open web fonts.md", + "time": "2018-03-08", + "user": "darksun" + }, + { + "file": "sources/tech/20180307 3 open source tools for scientific publishing.md", + "time": "2018-03-12", + "user": "darksun" + }, + { + "file": "sources/tech/20180307 Protecting Code Integrity with PGP - Part 4- Moving Your Master Key to Offline Storage.md", + "time": "2018-03-13", + "user": "darksun" + }, + { + "file": "sources/tech/20180307 What Is sosreport- How To Create sosreport.md", + "time": "2018-03-08", + "user": "darksun" + }, + { + "file": "sources/tech/20180309 A Comparison of Three Linux -App Stores.md", + "time": "2018-03-12", + "user": "darksun" + }, + { + "file": "sources/tech/20180312 ddgr - A Command Line Tool To Search DuckDuckGo From The Terminal.md", + "time": "2018-03-29", + "user": "darksun" + }, + { + "file": "sources/tech/20180314 5 open source card and board games for Linux.md", + "time": "2018-03-20", + "user": "darksun" + }, + { + "file": "sources/tech/20180314 Protecting Code Integrity with PGP - Part 5- Moving Subkeys to a Hardware Device.md", + "time": "2018-03-21", + "user": "darksun" + }, + { + "file": "sources/tech/20180321 Protecting Code Integrity with PGP - Part 6- Using PGP with Git.md", + "time": "2018-03-22", + "user": "darksun" + }, + { + "file": "sources/tech/20180911 Know Your Storage- Block, File - Object.md", + "time": "2018-10-15", + "user": "lctt-bot" + }, + { + "file": "sources/tech/20180324 Memories of writing a parser for man pages.md", + "time": "2018-04-08", + "user": "darksun" + }, + { + "file": "sources/tech/20180326 How to create an open source stack using EFK.md", + "time": "2018-03-29", + "user": "darksun" + }, + { + "file": "sources/tech/20180326 Manage your workstation with Ansible- Automating configuration.md", + "time": "2018-03-29", + "user": "darksun" + }, + { + "file": "sources/tech/20181115 11 Things To Do After Installing elementary OS 5 Juno.md", + "time": "2018-11-16", + "user": "darksun" + }, + { + "file": "sources/tech/20180327 Anna A KVS for any scale.md", + "time": "2018-04-06", + "user": "Ezio" + }, + { + "file": "sources/tech/20180330 Go on very small hardware Part 1.md", + "time": "2018-04-21", + "user": "Ezio" + }, + { + "file": "sources/tech/20180403 Open Source Accounting Program GnuCash 3.0 Released With a New CSV Importer Tool Rewritten in C plus plus.md", + "time": "2018-04-06", + "user": "Ezio" + }, + { + "file": "sources/tech/20180404 Bring some JavaScript to your Java enterprise with Vert.x.md", + "time": "2018-05-31", + "user": "darksun" + }, + { + "file": "sources/tech/20180406 MX Linux- A Mid-Weight Distro Focused on Simplicity.md", + "time": "2018-04-09", + "user": "darksun" + }, + { + "file": "sources/tech/20180407 12 Best GTK Themes for Ubuntu and other Linux Distributions.md", + "time": "2018-04-12", + "user": "darksun" + }, + { + "file": "sources/tech/20180411 5 Best Feed Reader Apps for Linux.md", + "time": "2018-04-17", + "user": "darksun" + }, + { + "file": "sources/tech/20180411 How To Setup Static File Server Instantly.md", + "time": "2018-04-16", + "user": "darksun" + }, + { + "file": "sources/tech/20180411 Replicate your custom Linux settings with DistroTweaks.md", + "time": "2018-04-13", + "user": "darksun" + }, + { + "file": "sources/tech/20180412 Getting started with Jenkins Pipelines.md", + "time": "2018-06-13", + "user": "Xingyu.Wang" + }, + { + "file": "sources/tech/20180413 Redcore Linux Makes Gentoo Easy.md", + "time": "2018-04-16", + "user": "darksun" + }, + { + "file": "sources/tech/20180414 Go on very small hardware Part 2.md", + "time": "2018-04-21", + "user": "Ezio" + }, + { + "file": "sources/tech/20180416 Cgo and Python.md", + "time": "2018-04-21", + "user": "Ezio" + }, + { + "file": "sources/tech/20180416 How To Resize Active-Primary root Partition Using GParted Utility.md", + "time": "2018-04-17", + "user": "darksun" + }, + { + "file": "sources/tech/20180419 Migrating to Linux- Network and System Settings.md", + "time": "2018-04-23", + "user": "darksun" + }, + { + "file": "sources/tech/20180419 Writing Advanced Web Applications with Go.md", + "time": "2018-04-21", + "user": "Ezio" + }, + { + "file": "sources/tech/20180420 A handy way to add free books to your eReader.md", + "time": "2018-04-23", + "user": "darksun" + }, + { + "file": "sources/tech/20180420 How To Remove Password From A PDF File in Linux.md", + "time": "2018-04-24", + "user": "darksun" + }, + { + "file": "sources/tech/20180422 Command Line Tricks For Data Scientists - kade killary.md", + "time": "2018-06-04", + "user": "darksun" + }, + { + "file": "sources/tech/20180423 Breach detection with Linux filesystem forensics - Opensource.com.md", + "time": "2018-04-24", + "user": "darksun" + }, + { + "file": "sources/tech/20180423 Managing virtual environments with Vagrant.md", + "time": "2018-04-24", + "user": "darksun" + }, + { + "file": "sources/tech/20180730 50 Best Ubuntu Apps You Should Be Using Right Now.md", + "time": "2018-08-14", + "user": "darksun" + }, + { + "file": "sources/tech/20180425 An introduction to the GNU Core Utilities - Opensource.com.md", + "time": "2018-04-26", + "user": "geekpi" + }, + { + "file": "sources/tech/20180723 System Snapshot And Restore Utility For Linux.md", + "time": "2018-08-19", + "user": "darksun" + }, + { + "file": "sources/tech/20180428 A Beginners Guide To Flatpak.md", + "time": "2018-05-02", + "user": "darksun" + }, + { + "file": "sources/tech/20180429 The Easiest PDO Tutorial (Basics).md", + "time": "2018-06-19", + "user": "darksun" + }, + { + "file": "sources/tech/20180430 PCGen- An easy way to generate RPG characters.md", + "time": "2018-05-02", + "user": "darksun" + }, + { + "file": "sources/tech/20180503 11 Methods To Find System-Server Uptime In Linux.md", + "time": "2018-05-14", + "user": "darksun" + }, + { + "file": "sources/tech/20180503 How the four components of a distributed tracing system work together.md", + "time": "2018-05-14", + "user": "darksun" + }, + { + "file": "sources/tech/20180509 4MLinux Revives Your Older Computer [Review].md", + "time": "2018-05-10", + "user": "darksun" + }, + { + "file": "sources/tech/20180511 MidnightBSD Could Be Your Gateway to FreeBSD.md", + "time": "2018-05-14", + "user": "darksun" + }, + { + "file": "sources/tech/20180514 MapTool- A robust, flexible virtual tabletop for RPGs.md", + "time": "2018-05-24", + "user": "darksun" + }, + { + "file": "sources/tech/20180515 Termux turns Android into a Linux development environment.md", + "time": "2018-05-18", + "user": "darksun" + }, + { + "file": "sources/tech/20180518 What-s a hero without a villain- How to add one to your Python game.md", + "time": "2018-05-21", + "user": "darksun" + }, + { + "file": "sources/tech/20180522 Advanced use of the less text file viewer in Linux.md", + "time": "2018-05-24", + "user": "darksun" + }, + { + "file": "sources/tech/20180920 Distributed tracing in a microservices world.md", + "time": "2018-09-27", + "user": "darksun" + }, + { + "file": "sources/tech/20180329 Python ChatOps libraries- Opsdroid and Errbot.md", + "time": "2018-10-07", + "user": "Xingyu.Wang" + }, + { + "file": "sources/tech/20180524 TrueOS- A Simple BSD Distribution for the Desktop Users.md", + "time": "2018-06-01", + "user": "darksun" + }, + { + "file": "sources/tech/20180525 How to Set Different Wallpaper for Each Monitor in Linux.md", + "time": "2018-05-31", + "user": "darksun" + }, + { + "file": "sources/tech/20180529 How the Go runtime implements maps efficiently.md", + "time": "2018-07-04", + "user": "Ezio" + }, + { + "file": "sources/tech/20180529 Manage your workstation with Ansible- Configure desktop settings.md", + "time": "2018-05-31", + "user": "darksun" + }, + { + "file": "sources/tech/20180530 Introduction to the Pony programming language.md", + "time": "2018-05-31", + "user": "darksun" + }, + { + "file": "sources/tech/20180914 A day in the life of a log message.md", + "time": "2018-09-16", + "user": "darksun" + }, + { + "file": "sources/tech/20180531 Qalculate- - The Best Calculator Application in The Entire Universe.md", + "time": "2018-06-04", + "user": "darksun" + }, + { + "file": "sources/tech/20180601 3 open source music players for Linux.md", + "time": "2018-06-04", + "user": "darksun" + }, + { + "file": "sources/tech/20180601 Get Started with Snap Packages in Linux.md", + "time": "2018-06-04", + "user": "darksun" + }, + { + "file": "sources/tech/20180604 4 Firefox extensions worth checking out.md", + "time": "2018-06-06", + "user": "darksun" + }, + { + "file": "sources/tech/20180604 BootISO - A Simple Bash Script To Securely Create A Bootable USB Device From ISO File.md", + "time": "2018-08-03", + "user": "darksun" + }, + { + "file": "sources/tech/20180605 How to use autofs to mount NFS shares.md", + "time": "2018-06-06", + "user": "darksun" + }, + { + "file": "sources/tech/20180605 Sound themes in Linux- What every user should know.md", + "time": "2018-06-06", + "user": "darksun" + }, + { + "file": "sources/tech/20180606 Working with modules in Fedora 28.md", + "time": "2018-06-08", + "user": "darksun" + }, + { + "file": "sources/tech/20180608 How to Install and Use Flatpak on Linux.md", + "time": "2018-06-11", + "user": "darksun" + }, + { + "file": "sources/tech/20180608 How to use screen scraping tools to extract data from the web.md", + "time": "2018-06-19", + "user": "darksun" + }, + { + "file": "sources/tech/20180609 4 tips for getting an older relative online with Linux.md", + "time": "2018-06-11", + "user": "darksun" + }, + { + "file": "sources/tech/20180817 AryaLinux- A Distribution and a Platform.md", + "time": "2018-08-19", + "user": "darksun" + }, + { + "file": "sources/tech/20180611 3 open source alternatives to Adobe Lightroom.md", + "time": "2018-06-15", + "user": "darksun" + }, + { + "file": "sources/tech/20180612 7 open source tools to make literature reviews easy.md", + "time": "2018-06-15", + "user": "darksun" + }, + { + "file": "sources/tech/20180612 Using Ledger for YNAB-like envelope budgeting.md", + "time": "2018-07-05", + "user": "darksun" + }, + { + "file": "sources/tech/20180614 Bash tips for everyday at the command line.md", + "time": "2018-06-19", + "user": "darksun" + }, + { + "file": "sources/tech/20180914 Freespire Linux- A Great Desktop for the Open Source Purist.md", + "time": "2018-09-18", + "user": "darksun" + }, + { + "file": "sources/tech/20180918 Cozy Is A Nice Linux Audiobook Player For DRM-Free Audio Files.md", + "time": "2018-09-19", + "user": "darksun" + }, + { + "file": "sources/tech/20180618 Write fast apps with Pronghorn, a Java framework.md", + "time": "2018-06-20", + "user": "darksun" + }, + { + "file": "sources/tech/20180621 How to connect to a remote desktop from Linux.md", + "time": "2018-06-28", + "user": "darksun" + }, + { + "file": "sources/tech/20180621 Troubleshooting a Buildah script.md", + "time": "2018-06-28", + "user": "darksun" + }, + { + "file": "sources/tech/20180622 Use LVM to Upgrade Fedora.md", + "time": "2018-06-28", + "user": "darksun" + }, + { + "file": "sources/tech/20180806 Recreate Famous Data Decryption Effect Seen On Sneakers Movie.md", + "time": "2018-08-23", + "user": "darksun" + }, + { + "file": "sources/tech/20180625 The life cycle of a software bug.md", + "time": "2018-06-28", + "user": "darksun" + }, + { + "file": "sources/tech/20180626 How To Search If A Package Is Available On Your Linux Distribution Or Not.md", + "time": "2018-06-28", + "user": "darksun" + }, + { + "file": "sources/tech/20180629 100 Best Ubuntu Apps.md", + "time": "2018-07-02", + "user": "darksun" + }, + { + "file": "sources/tech/20180629 Discover hidden gems in LibreOffice.md", + "time": "2018-07-02", + "user": "darksun" + }, + { + "file": "sources/tech/20180629 How To Get Flatpak Apps And Games Built With OpenGL To Work With Proprietary Nvidia Graphics Drivers.md", + "time": "2018-07-04", + "user": "darksun" + }, + { + "file": "sources/tech/20180629 Is implementing and managing Linux applications becoming a snap.md", + "time": "2018-07-04", + "user": "darksun" + }, + { + "file": "sources/tech/20180629 SoCLI - Easy Way To Search And Browse Stack Overflow From The Terminal.md", + "time": "2018-07-02", + "user": "darksun" + }, + { + "file": "sources/tech/20180701 12 Things to do After Installing Linux Mint 19.md", + "time": "2018-07-04", + "user": "darksun" + }, + { + "file": "sources/tech/20180702 5 open source alternatives to Skype.md", + "time": "2018-07-04", + "user": "darksun" + }, + { + "file": "sources/tech/20180702 Diggs v4 launch an optimism born of necessity.md", + "time": "2018-07-05", + "user": "geekpi" + }, + { + "file": "sources/tech/20180816 Designing your garden with Edraw Max - FOSS adventures.md", + "time": "2018-08-18", + "user": "darksun" + }, + { + "file": "sources/tech/20180703 10 killer tools for the admin in a hurry.md", + "time": "2018-07-05", + "user": "darksun" + }, + { + "file": "sources/tech/20180703 AGL Outlines Virtualization Scheme for the Software Defined Vehicle.md", + "time": "2018-07-04", + "user": "Ezio" + }, + { + "file": "sources/tech/20180704 BASHing data- Truncated data items.md", + "time": "2018-07-05", + "user": "darksun" + }, + { + "file": "sources/tech/20180706 Using Ansible to set up a workstation.md", + "time": "2018-07-09", + "user": "darksun" + }, + { + "file": "sources/tech/20180708 simple and elegant free podcast player.md", + "time": "2018-07-09", + "user": "darksun" + }, + { + "file": "sources/tech/20180709 5 Firefox extensions to protect your privacy.md", + "time": "2018-07-13", + "user": "darksun" + }, + { + "file": "sources/tech/20180924 5 ways to play old-school games on a Raspberry Pi.md", + "time": "2018-09-25", + "user": "darksun" + }, + { + "file": "sources/tech/20180710 The aftermath of the Gentoo GitHub hack.md", + "time": "2018-07-13", + "user": "darksun" + }, + { + "file": "sources/tech/20180710 Users, Groups, and Other Linux Beasts.md", + "time": "2018-07-16", + "user": "darksun" + }, + { + "file": "sources/tech/20180711 5 open source racing and flying games for Linux.md", + "time": "2018-07-16", + "user": "darksun" + }, + { + "file": "sources/tech/20180923 Gunpoint is a Delight for Stealth Game Fans.md", + "time": "2018-09-25", + "user": "darksun" + }, + { + "file": "sources/tech/20180719 Building tiny container images.md", + "time": "2018-08-02", + "user": "darksun" + }, + { + "file": "sources/tech/20180919 Streama - Setup Your Own Streaming Media Server In Minutes.md", + "time": "2018-09-20", + "user": "darksun" + }, + { + "file": "sources/tech/20180920 Record Screen in Ubuntu Linux With Kazam -Beginner-s Guide.md", + "time": "2018-09-21", + "user": "darksun" + }, + { + "file": "sources/tech/20181015 An introduction to Ansible Operators in Kubernetes.md", + "time": "2018-10-18", + "user": "darksun" + }, + { + "file": "sources/tech/20180724 How To Mount Google Drive Locally As Virtual File System In Linux.md", + "time": "2018-07-26", + "user": "darksun" + }, + { + "file": "sources/tech/20180725 Best Online Linux Terminals and Online Bash Editors.md", + "time": "2018-07-30", + "user": "darksun" + }, + { + "file": "sources/tech/20180828 Linux for Beginners- Moving Things Around.md", + "time": "2018-09-03", + "user": "darksun" + }, + { + "file": "sources/tech/20180816 Garbage collection in Perl 6.md", + "time": "2018-08-17", + "user": "darksun" + }, + { + "file": "sources/tech/20180727 4 Ways to Customize Xfce and Give it a Modern Look.md", + "time": "2018-07-30", + "user": "darksun" + }, + { + "file": "sources/tech/20180727 Download Subtitles Via Right Click From File Manager Or Command Line With OpenSubtitlesDownload.py.md", + "time": "2018-08-02", + "user": "darksun" + }, + { + "file": "sources/tech/20180829 Containers in Perl 6.md", + "time": "2018-08-31", + "user": "darksun" + }, + { + "file": "sources/tech/20180731 What-s in a container image- Meeting the legal challenges.md", + "time": "2018-08-03", + "user": "darksun" + }, + { + "file": "sources/tech/20180801 Getting started with Standard Notes for encrypted note-taking.md", + "time": "2018-08-03", + "user": "darksun" + }, + { + "file": "sources/tech/20180801 Hiri is a Linux Email Client Exclusively Created for Microsoft Exchange.md", + "time": "2018-08-03", + "user": "darksun" + }, + { + "file": "sources/tech/20180801 Migrating Perl 5 code to Perl 6.md", + "time": "2018-08-03", + "user": "darksun" + }, + { + "file": "sources/tech/20180810 Strawberry- Quality sound, open source music player.md", + "time": "2018-08-14", + "user": "darksun" + }, + { + "file": "sources/tech/20180802 Walkthrough On How To Use GNOME Boxes.md", + "time": "2018-08-03", + "user": "darksun" + }, + { + "file": "sources/tech/20180803 How to use Fedora Server to create a router - gateway.md", + "time": "2018-08-06", + "user": "DarkSun" + }, + { + "file": "sources/tech/20180830 A quick guide to DNF for yum users.md", + "time": "2018-09-03", + "user": "darksun" + }, + { + "file": "sources/tech/20180806 How ProPublica Illinois uses GNU Make to load 1.4GB of data every day.md", + "time": "2018-08-08", + "user": "darksun" + }, + { + "file": "sources/tech/20181003 Oomox - Customize And Create Your Own GTK2, GTK3 Themes.md", + "time": "2018-10-09", + "user": "darksun" + }, + { + "file": "sources/tech/20180822 9 flowchart and diagramming tools for Linux.md", + "time": "2018-08-23", + "user": "DarkSun" + }, + { + "file": "sources/tech/20180806 Use Gstreamer and Python to rip CDs.md", + "time": "2018-08-08", + "user": "darksun" + }, + { + "file": "sources/tech/20180929 Use Cozy to Play Audiobooks in Linux.md", + "time": "2018-09-30", + "user": "darksun" + }, + { + "file": "sources/tech/20180514 Tuptime - A Tool To Report The Historical Uptime Of Linux System.md", + "time": "2018-08-10", + "user": "darksun" + }, + { + "file": "sources/tech/20180809 Getting started with Postfix, an open source mail transfer agent.md", + "time": "2018-08-10", + "user": "darksun" + }, + { + "file": "sources/tech/20180830 How to scale your website across all mobile devices.md", + "time": "2018-09-04", + "user": "darksun" + }, + { + "file": "sources/tech/20180809 Perform robust unit tests with PyHamcrest.md", + "time": "2018-08-10", + "user": "darksun" + }, + { + "file": "sources/tech/20180802 Top 5 CAD Software Available for Linux in 2018.md", + "time": "2018-08-19", + "user": "darksun" + }, + { + "file": "sources/tech/20180810 Use Plank On Multiple Monitors Without Creating Multiple Docks With autoplank.md", + "time": "2018-08-14", + "user": "darksun" + }, + { + "file": "sources/tech/20180925 Taking the Audiophile Linux distro for a spin.md", + "time": "2018-09-26", + "user": "darksun" + }, + { + "file": "sources/tech/20180828 An Introduction to Quantum Computing with Open Source Cirq Framework.md", + "time": "2018-08-29", + "user": "darksun" + }, + { + "file": "sources/tech/20180814 5 open source strategy and simulation games for Linux.md", + "time": "2018-08-15", + "user": "darksun" + }, + { + "file": "sources/tech/20181018 4 open source alternatives to Microsoft Access.md", + "time": "2018-10-19", + "user": "darksun" + }, + { + "file": "sources/tech/20180716 Users, Groups and Other Linux Beasts- Part 2.md", + "time": "2018-07-24", + "user": "darksun" + }, + { + "file": "sources/tech/20180814 HTTP request routing and validation with gorilla-mux.md", + "time": "2018-08-16", + "user": "darksun" + }, + { + "file": "sources/tech/20180815 Happy birthday, GNOME- 6 reasons to love this Linux desktop.md", + "time": "2018-08-16", + "user": "darksun" + }, + { + "file": "sources/tech/20180817 Cloudgizer- An introduction to a new open source web development tool.md", + "time": "2018-08-18", + "user": "darksun" + }, + { + "file": "sources/tech/20140929 A Word from The Beegoist - Richard Kenneth Eng - Medium.md", + "time": "2018-08-19", + "user": "darksun" + }, + { + "file": "sources/tech/20180828 Orion Is A QML - C-- Twitch Desktop Client With VODs And Chat Support.md", + "time": "2018-08-31", + "user": "darksun" + }, + { + "file": "sources/tech/20180906 What a shell dotfile can do for you.md", + "time": "2018-09-07", + "user": "darksun" + }, + { + "file": "sources/tech/20180912 How subroutine signatures work in Perl 6.md", + "time": "2018-09-13", + "user": "darksun" + }, + { + "file": "sources/tech/20180912 How to turn on an LED with Fedora IoT.md", + "time": "2018-09-13", + "user": "darksun" + }, + { + "file": "sources/tech/20181005 Dbxfs - Mount Dropbox Folder Locally As Virtual File System In Linux.md", + "time": "2018-10-08", + "user": "darksun" + }, + { + "file": "sources/tech/20181005 How to use Kolibri to access educational material offline.md", + "time": "2018-10-08", + "user": "darksun" + }, + { + "file": "sources/tech/20181011 The First Beta of Haiku is Released After 16 Years of Development.md", + "time": "2018-10-12", + "user": "darksun" + }, + { + "file": "sources/tech/20181016 piwheels- Speedy Python package installation for the Raspberry Pi.md", + "time": "2018-10-18", + "user": "darksun" + }, + { + "file": "sources/tech/20181018 TimelineJS- An interactive, JavaScript timeline building tool.md", + "time": "2018-10-19", + "user": "darksun" + } + ] +} From 63bb15019965203ff41efc0be71ce6120e89c6b2 Mon Sep 17 00:00:00 2001 From: darksun Date: Fri, 30 Nov 2018 23:39:05 +0800 Subject: [PATCH 03/12] =?UTF-8?q?=E9=80=89=E9=A2=98:=20An=20introduction?= =?UTF-8?q?=20to=20the=20Flask=20Python=20web=20app=20framework?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...n to the Flask Python web app framework.md | 451 ++++++++++++++++++ 1 file changed, 451 insertions(+) create mode 100644 sources/tech/20180402 An introduction to the Flask Python web app framework.md diff --git a/sources/tech/20180402 An introduction to the Flask Python web app framework.md b/sources/tech/20180402 An introduction to the Flask Python web app framework.md new file mode 100644 index 0000000000..4b07338bc5 --- /dev/null +++ b/sources/tech/20180402 An introduction to the Flask Python web app framework.md @@ -0,0 +1,451 @@ +[#]: collector: (lujun9972) +[#]: translator: ( ) +[#]: reviewer: ( ) +[#]: publisher: ( ) +[#]: subject: (An introduction to the Flask Python web app framework) +[#]: via: (https://opensource.com/article/18/4/flask) +[#]: author: (Nicholas Hunt-Walker https://opensource.com/users/nhuntwalker) +[#]: url: ( ) + +An introduction to the Flask Python web app framework +====== +In the first part in a series comparing Python frameworks, learn about Flask. +![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/python-programming-code-keyboard.png?itok=fxiSpmnd) + +If you're developing a web app in Python, chances are you're leveraging a framework. A [framework][1] "is a code library that makes a developer's life easier when building reliable, scalable, and maintainable web applications" by providing reusable code or extensions for common operations. There are a number of frameworks for Python, including [Flask][2], [Tornado][3], [Pyramid][4], and [Django][5]. New Python developers often ask: Which framework should I use? + + * New visitors to the site should be able to register new accounts. + * Registered users can log in, log out, see information for their profiles, and edit their information. + * Registered users can create new task items, see their existing tasks, and edit existing tasks. + + + +This series is designed to help developers answer that question by comparing those four frameworks. To compare their features and operations, I'll take each one through the process of constructing an API for a simple To-Do List web application. The API is itself fairly straightforward: + +All this rounds out to a compact set of API endpoints that each backend must implement, along with the allowed HTTP methods: + + * `GET /` + * `POST /accounts` + * `POST /accounts/login` + * `GET /accounts/logout` + * `GET, PUT, DELETE /accounts/` + * `GET, POST /accounts//tasks` + * `GET, PUT, DELETE /accounts//tasks/` + + + +Each framework has a different way to put together its routes, models, views, database interaction, and overall application configuration. I'll describe those aspects of each framework in this series, which will begin with Flask. + +### Flask startup and configuration + +Like most widely used Python libraries, the Flask package is installable from the [Python Package Index][6] (PPI). First create a directory to work in (something like `flask_todo` is a fine directory name) then install the `flask` package. You'll also want to install `flask-sqlalchemy` so your Flask application has a simple way to talk to a SQL database. + +I like to do this type of work within a Python 3 virtual environment. To get there, enter the following on the command line: + +``` +$ mkdir flask_todo +$ cd flask_todo +$ pipenv install --python 3.6 +$ pipenv shell +(flask-someHash) $ pipenv install flask flask-sqlalchemy +``` + +If you want to turn this into a Git repository, this is a good place to run `git init`. It'll be the root of the project, and if you want to export the codebase to a different machine, it will help to have all the necessary setup files here. + +A good way to get moving is to turn the codebase into an installable Python distribution. At the project's root, create `setup.py` and a directory called `todo` to hold the source code. + +The `setup.py` should look something like this: + +``` +from setuptools import setup, find_packages + +requires = [ +    'flask', +    'flask-sqlalchemy', +    'psycopg2', +] + +setup( +    name='flask_todo', +    version='0.0', +    description='A To-Do List built with Flask', +    author='', +    author_email='', +    keywords='web flask', +    packages=find_packages(), +    include_package_data=True, +    install_requires=requires +) +``` + +This way, whenever you want to install or deploy your project, you'll have all the necessary packages in the `requires` list. You'll also have everything you need to set up and install the package in `site-packages`. For more information on how to write an installable Python distribution, check out [the docs on setup.py][7]. + +Within the `todo` directory containing your source code, create an `app.py` file and a blank `__init__.py` file. The `__init__.py` file allows you to import from `todo` as if it were an installed package. The `app.py` file will be the application's root. This is where all the `Flask` application goodness will go, and you'll create an environment variable that points to that file. If you're using `pipenv` (like I am), you can locate your virtual environment with `pipenv --venv` and set up that environment variable in your environment's `activate` script. + +``` +# in your activate script, probably at the bottom (but anywhere will do) + +export FLASK_APP=$VIRTUAL_ENV/../todo/app.py +export DEBUG='True' +``` + +When you installed `Flask`, you also installed the `flask` command-line script. Typing `flask run` will prompt the virtual environment's Flask package to run an HTTP server using the `app` object in whatever script the `FLASK_APP` environment variable points to. The script above also includes an environment variable named `DEBUG` that will be used a bit later. + +Let's talk about this `app` object. + +In `todo/app.py`, you'll create an `app` object, which is an instance of the `Flask` object. It'll act as the central configuration object for the entire application. It's used to set up pieces of the application required for extended functionality, e.g., a database connection and help with authentication. + +It's regularly used to set up the routes that will become the application's points of interaction. To explain what this means, let's look at the code it corresponds to. + +``` +from flask import Flask + +app = Flask(__name__) + +@app.route('/') +def hello_world(): +    """Print 'Hello, world!' as the response body.""" +    return 'Hello, world!' +``` + +This is the most basic complete Flask application. `app` is an instance of `Flask`, taking in the `__name__` of the script file. This lets Python know how to import from files relative to this one. The `app.route` decorator decorates the first **view** function; it can specify one of the routes used to access the application. (We'll look at this later.) + +Any view you specify must be decorated by `app.route` to be a functional part of the application. You can have as many functions as you want scattered across the application, but in order for that functionality to be accessible from anything external to the application, you must decorate that function and specify a route to make it into a view. + +In the example above, when the app is running and accessed at `http://domainname/`, a user will receive `"Hello, World!"` as a response. + +### Connecting the database in Flask + +While the code example above represents a complete Flask application, it doesn't do anything interesting. One interesting thing a web application can do is persist user data, but it needs the help of and connection to a database. + +Flask is very much a "do it yourself" web framework. This means there's no built-in database interaction, but the `flask-sqlalchemy` package will connect a SQL database to a Flask application. The `flask-sqlalchemy` package needs just one thing to connect to a SQL database: The database URL. + +Note that a wide variety of SQL database management systems can be used with `flask-sqlalchemy`, as long as the DBMS has an intermediary that follows the [DBAPI-2 standard][8]. In this example, I'll use PostgreSQL (mainly because I've used it a lot), so the intermediary to talk to the Postgres database is the `psycopg2` package. Make sure `psycopg2` is installed in your environment and include it in the list of required packages in `setup.py`. You don't have to do anything else with it; `flask-sqlalchemy` will recognize Postgres from the database URL. + +Flask needs the database URL to be part of its central configuration through the `SQLALCHEMY_DATABASE_URI` attribute. A quick and dirty solution is to hardcode a database URL into the application. + +``` +# top of app.py +from flask import Flask +from flask_sqlalchemy import SQLAlchemy + +app = Flask(__name__) +app.config['SQLALCHEMY_DATABASE_URI'] = 'postgres://localhost:5432/flask_todo' +db = SQLAlchemy(app) +``` + +However, this is not a sustainable solution. If you change databases or don't want your database URL visible in source control, you'll have to take extra steps to ensure your information is appropriate for the environment. + +You can make things simpler by using environment variables. They will ensure that, no matter what machine the code runs on, it always points at the right stuff if that stuff is configured in the running environment. It also ensures that, even though you need that information to run the application, it never shows up as a hardcoded value in source control. + +In the same place you declared `FLASK_APP`, declare a `DATABASE_URL` pointing to the location of your Postgres database. Development tends to work locally, so just point to your local database. + +``` +# also in your activate script + +export DATABASE_URL='postgres://localhost:5432/flask_todo' +``` + +Now in `app.py`, include the database URL in your app configuration. + +``` +app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('DATABASE_URL', '') +db = SQLAlchemy(app) +``` + +And just like that, your application has a database connection! + +### Defining objects in Flask + +Having a database to talk to is a good first step. Now it's time to define some objects to fill that database. + +In application development, a "model" refers to the data representation of some real or conceptual object. For example, if you're building an application for a car dealership, you may define a `Car` model that encapsulates all of a car's attributes and behavior. + +In this case, you're building a To-Do List with Tasks, and each Task belongs to a User. Before you think too deeply about how they're related to each other, start by defining objects for Tasks and Users. + +The `flask-sqlalchemy` package leverages [SQLAlchemy][9] to set up and inform the database structure. You'll define a model that will live in the database by inheriting from the `db.Model` object and define the attributes of those models as `db.Column` instances. For each column, you must specify a data type, so you'll pass that data type into the call to `db.Column` as the first argument. + +Because the model definition occupies a different conceptual space than the application configuration, make `models.py` to hold model definitions separate from `app.py`. The Task model should be constructed to have the following attributes: + + * `id`: a value that's a unique identifier to pull from the database + * `name`: the name or title of the task that the user will see when the task is listed + * `note`: any extra comments that a person might want to leave with their task + * `creation_date`: the date and time the task was created + * `due_date`: the date and time the task is due to be completed (if at all) + * `completed`: a way to indicate whether or not the task has been completed + + + +Given this attribute list for Task objects, the application's `Task` object can be defined like so: + +``` +from .app import db +from datetime import datetime + +class Task(db.Model): +    """Tasks for the To Do list.""" +    id = db.Column(db.Integer, primary_key=True) +    name = db.Column(db.Unicode, nullable=False) +    note = db.Column(db.Unicode) +    creation_date = db.Column(db.DateTime, nullable=False) +    due_date = db.Column(db.DateTime) +    completed = db.Column(db.Boolean, default=False) + +    def __init__(self, *args, **kwargs): +        """On construction, set date of creation.""" +        super().__init__(*args, **kwargs) +        self.creation_date = datetime.now() +``` + +Note the extension of the class constructor method. At the end of the day, any model you construct is still a Python object and therefore must go through construction in order to be instantiated. It's important to ensure that the creation date of the model instance reflects its actual date of creation. You can explicitly set that relationship by effectively saying, "when an instance of this model is constructed, record the date and time and set it as the creation date." + +### Model relationships + +In a given web application, you may want to be able to express relationships between objects. In the To-Do List example, users own multiple tasks, and each task is owned by only one user. This is an example of a "many-to-one" relationship, also known as a foreign key relationship, where the tasks are the "many" and the user owning those tasks is the "one." + +In Flask, a many-to-one relationship can be specified using the `db.relationship` function. First, build the User object. + +``` +class User(db.Model): +    """The User object that owns tasks.""" +    id = db.Column(db.Integer, primary_key=True) +    username = db.Column(db.Unicode, nullable=False) +    email = db.Column(db.Unicode, nullable=False) +    password = db.Column(db.Unicode, nullable=False) +    date_joined = db.Column(db.DateTime, nullable=False) +    token = db.Column(db.Unicode, nullable=False) + +    def __init__(self, *args, **kwargs): +        """On construction, set date of creation.""" +        super().__init__(*args, **kwargs) +        self.date_joined = datetime.now() +        self.token = secrets.token_urlsafe(64) +``` + +It looks very similar to the Task object; you'll find that most objects have the same basic format of class attributes as table columns. Every once in a while, you'll run into something a little different, including some multiple-inheritance magic, but this is the norm. + +Now that the `User` model is created, you can set up the foreign key relationship. For the "many," set fields for the `user_id` of the `User` that owns this task, as well as the `user` object with that ID. Also make sure to include a keyword argument (`back_populates`) that updates the User model when the task gets a user as an owner. + +For the "one," set a field for the `tasks` the specific user owns. Similar to maintaining the two-way relationship on the Task object, set a keyword argument on the User's relationship field to update the Task when it is assigned to a user. + +``` +# on the Task object +user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) +user = db.relationship("user", back_populates="tasks") + +# on the User object +tasks = db.relationship("Task", back_populates="user") +``` + +### Initializing the database + +Now that the models and model relationships are set, start setting up your database. Flask doesn't come with its own database-management utility, so you'll have to write your own (to some degree). You don't have to get fancy with it; you just need something to recognize what tables are to be created and some code to create them (or drop them should the need arise). If you need something more complex, like handling updates to database tables (i.e., database migrations), you'll want to look into a tool like [Flask-Migrate][10] or [Flask-Alembic][11]. + +Create a script called `initializedb.py` next to `setup.py` for managing the database. (Of course, it doesn't need to be called this, but why not give names that are appropriate to a file's function?) Within `initializedb.py`, import the `db` object from `app.py` and use it to create or drop tables. `initializedb.py` should end up looking something like this: + +``` +from todo.app import db +import os + +if bool(os.environ.get('DEBUG', '')): +    db.drop_all() +db.create_all() +``` + +If a `DEBUG` environment variable is set, drop tables and rebuild. Otherwise, just create the tables once and you're good to go. + +### Views and URL config + +The last bits needed to connect the entire application are the views and routes. In web development, a "view" (in concept) is functionality that runs when a specific access point (a "route") in your application is hit. These access points appear as URLs: paths to functionality in an application that return some data or handle some data that has been provided. The views will be logical structures that handle specific HTTP requests from a given client and return some HTTP response to that client. + +In Flask, views appear as functions; for example, see the `hello_world` view above. For simplicity, here it is again: + +``` +@app.route('/') +def hello_world(): +    """Print 'Hello, world!' as the response body.""" +    return 'Hello, world!' +``` + +When the route of `http://domainname/` is accessed, the client receives the response, "Hello, world!" + +With Flask, a function is marked as a view when it is decorated by `app.route`. In turn, `app.route` adds to the application's central configuration a map from the specified route to the function that runs when that route is accessed. You can use this to start building out the rest of the API. + +Start with a view that handles only `GET` requests, and respond with the JSON representing all the routes that will be accessible and the methods that can be used to access them. + +``` +from flask import jsonify + +@app.route('/api/v1', methods=["GET"]) +def info_view(): +    """List of routes for this API.""" +    output = { +        'info': 'GET /api/v1', +        'register': 'POST /api/v1/accounts', +        'single profile detail': 'GET /api/v1/accounts/', +        'edit profile': 'PUT /api/v1/accounts/', +        'delete profile': 'DELETE /api/v1/accounts/', +        'login': 'POST /api/v1/accounts/login', +        'logout': 'GET /api/v1/accounts/logout', +        "user's tasks": 'GET /api/v1/accounts//tasks', +        "create task": 'POST /api/v1/accounts//tasks', +        "task detail": 'GET /api/v1/accounts//tasks/', +        "task update": 'PUT /api/v1/accounts//tasks/', +        "delete task": 'DELETE /api/v1/accounts//tasks/' +    } +    return jsonify(output) +``` + +Since you want your view to handle one specific type of HTTP request, use `app.route` to add that restriction. The `methods` keyword argument will take a list of strings as a value, with each string a type of possible HTTP method. In practice, you can use `app.route` to restrict to one or more types of HTTP request or accept any by leaving the `methods` keyword argument alone. + +Whatever you intend to return from your view function **must** be a string or an object that Flask turns into a string when constructing a properly formatted HTTP response. The exceptions to this rule are when you're trying to handle redirects and exceptions thrown by your application. What this means for you, the developer, is that you need to be able to encapsulate whatever response you're trying to send back to the client into something that can be interpreted as a string. + +A good structure that contains complexity but can still be stringified is a Python dictionary. Therefore, I recommend that, whenever you want to send some data to the client, you choose a Python `dict` with whatever key-value pairs you need to convey information. To turn that dictionary into a properly formatted JSON response, headers and all, pass it as an argument to Flask's `jsonify` function (`from flask import jsonify`). + +The view function above takes what is effectively a listing of every route that this API intends to handle and sends it to the client whenever the `http://domainname/api/v1` route is accessed. Note that, on its own, Flask supports routing to exactly matching URIs, so accessing that same route with a trailing `/` would create a 404 error. If you wanted to handle both with the same view function, you'd need stack decorators like so: + +``` +@app.route('/api/v1', methods=["GET"]) +@app.route('/api/v1/', methods=["GET"]) +def info_view(): +    # blah blah blah more code +``` + +An interesting case is that if the defined route had a trailing slash and the client asked for the route without the slash, you wouldn't need to double up on decorators. Flask would redirect the client's request appropriately. It's odd that it doesn't work both ways. + +### Flask requests and the DB + +At its base, a web framework's job is to handle incoming HTTP requests and return HTTP responses. The previously written view doesn't really have much to do with HTTP requests aside from the URI that was accessed. It doesn't process any data. Let's look at how Flask behaves when data needs handling. + +The first thing to know is that Flask doesn't provide a separate `request` object to each view function. It has **one** global request object that every view function can use, and that object is conveniently named `request` and is importable from the Flask package. + +The next thing is that Flask's route patterns can have a bit more nuance. One scenario is a hardcoded route that must be matched perfectly to activate a view function. Another scenario is a route pattern that can handle a range of routes, all mapping to one view by allowing a part of that route to be variable. If the route in question has a variable, the corresponding value can be accessed from the same-named variable in the view's parameter list. + +``` +@app.route('/a/sample//route) +def some_view(variable): +    # some code blah blah blah +``` + +To communicate with the database within a view, you must use the `db` object that was populated toward the top of the script. Its `session` attribute is your connection to the database when you want to make changes. If you just want to query for objects, the objects built from `db.Model` have their own database interaction layer through the `query` attribute. + +Finally, any response you want from a view that's more complex than a string must be built deliberately. Previously you built a response using a "jsonified" dictionary, but certain assumptions were made (e.g., 200 status code, status message "OK," Content-Type of "text/plain"). Any special sauce you want in your HTTP response must be added deliberately. + +Knowing these facts about working with Flask views allows you to construct a view whose job is to create new `Task` objects. Let's look at the code (below) and address it piece by piece. + +``` +from datetime import datetime +from flask import request, Response +from flask_sqlalchemy import SQLAlchemy +import json + +from .models import Task, User + +app = Flask(__name__) +app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('DATABASE_URL', '') +db = SQLAlchemy(app) + +INCOMING_DATE_FMT = '%d/%m/%Y %H:%M:%S' + +@app.route('/api/v1/accounts//tasks', methods=['POST']) +def create_task(username): +    """Create a task for one user.""" +    user = User.query.filter_by(username=username).first() +    if user: +        task = Task( +            name=request.form['name'], +            note=request.form['note'], +            creation_date=datetime.now(), +            due_date=datetime.strptime(due_date, INCOMING_DATE_FMT) if due_date else None, +            completed=bool(request.form['completed']), +            user_id=user.id, +        ) +        db.session.add(task) +        db.session.commit() +        output = {'msg': 'posted'} +        response = Response( +            mimetype="application/json", +            response=json.dumps(output), +            status=201 +        ) +        return response +``` + +Let's start with the `@app.route` decorator. The route is `'/api/v1/accounts//tasks'`, where `` is a route variable. Put angle brackets around any part of the route you want to be variable, then include that part of the route on the next line in the parameter list **with the same name**. The only parameters that should be in the parameter list should be the variables in your route. + +Next comes the query: + +``` +user = User.query.filter_by(username=username).first() +``` + +To look for one user by username, conceptually you need to look at all the User objects stored in the database and find the users with the username matching the one that was requested. With Flask, you can ask the `User` object directly through the `query` attribute for the instance matching your criteria. This type of query would provide a list of objects (even if it's only one object or none at all), so to get the object you want, just call `first()`. + +``` +task = Task( +    name=request.form['name'], +    note=request.form['note'], +    creation_date=datetime.now(), +    due_date=datetime.strptime(due_date, INCOMING_DATE_FMT) if due_date else None, +    completed=bool(request.form['completed']), +    user_id=user.id, +) +``` + +Whenever data is sent to the application, regardless of the HTTP method used, that data is stored on the `form` attribute of the `request` object. The name of the field on the frontend will be the name of the key mapped to that data in the `form` dictionary. It'll always come in the form of a string, so if you want your data to be a specific data type, you'll have to make it explicit by casting it as the appropriate type. + +The other thing to note is the assignment of the current user's user ID to the newly instantiated `Task`. This is how that foreign key relationship is maintained. + +``` +db.session.add(task) +db.session.commit() +``` + +Creating a new `Task` instance is great, but its construction has no inherent connection to tables in the database. In order to insert a new row into the corresponding SQL table, you must use the `session` attached to the `db` object. The `db.session.add(task)` stages the new `Task` instance to be added to the table, but doesn't add it yet. While it's done only once here, you can add as many things as you want before committing. The `db.session.commit()` takes all the staged changes, or "commits," and applies them to the corresponding tables in the database. + +``` +output = {'msg': 'posted'} +response = Response( +    mimetype="application/json", +    response=json.dumps(output), +    status=201 +) +``` + +The response is an actual instance of a `Response` object with its `mimetype`, body, and `status` set deliberately. The goal for this view is to alert the user they created something new. Seeing how this view is supposed to be part of a backend API that sends and receives JSON, the response body must be JSON serializable. A dictionary with a simple string message should suffice. Ensure that it's ready for transmission by calling `json.dumps` on your dictionary, which will turn your Python object into valid JSON. This is used instead of `jsonify`, as `jsonify` constructs an actual response object using its input as the response body. In contrast, `json.dumps` just takes a given Python object and converts it into a valid JSON string if possible. + +By default, the status code of any response sent with Flask will be `200`. That will work for most circumstances, where you're not trying to send back a specific redirection-level or error-level message. Since this case explicitly lets the frontend know when a new item has been created, set the status code to be `201`, which corresponds to creating a new thing. + +And that's it! That's a basic view for creating a new `Task` object in Flask given the current setup of your To-Do List application. Similar views could be constructed for listing, editing, and deleting tasks, but this example offers an idea of how it could be done. + +### The bigger picture + +There is much more that goes into an application than one view for creating new things. While I haven't discussed anything about authorization/authentication systems, testing, database migration management, cross-origin resource sharing, etc., the details above should give you more than enough to start digging into building your own Flask applications. + +Learn more Python at [PyCon Cleveland 2018][12]. + +-------------------------------------------------------------------------------- + +via: https://opensource.com/article/18/4/flask + +作者:[Nicholas Hunt-Walker][a] +选题:[lujun9972][b] +译者:[译者ID](https://github.com/译者ID) +校对:[校对者ID](https://github.com/校对者ID) + +本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出 + +[a]: https://opensource.com/users/nhuntwalker +[b]: https://github.com/lujun9972 +[1]: https://www.fullstackpython.com/web-frameworks.html +[2]: http://flask.pocoo.org/ +[3]: http://www.tornadoweb.org/en/stable/ +[4]: https://trypyramid.com/ +[5]: https://www.djangoproject.com/ +[6]: https://pypi.python.org +[7]: https://docs.python.org/3/distutils/setupscript.html +[8]: https://www.python.org/dev/peps/pep-0249/ +[9]: https://www.sqlalchemy.org/ +[10]: https://flask-migrate.readthedocs.io/en/latest/ +[11]: https://flask-alembic.readthedocs.io/en/stable/ +[12]: https://us.pycon.org/2018/ From ffa05ba0dce5509c1ed0acc188a7ff2a3347b696 Mon Sep 17 00:00:00 2001 From: darksun Date: Fri, 30 Nov 2018 23:46:36 +0800 Subject: [PATCH 04/12] =?UTF-8?q?=E9=80=89=E9=A2=98:=20An=20introduction?= =?UTF-8?q?=20to=20the=20Tornado=20Python=20web=20app=20framework?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...to the Tornado Python web app framework.md | 590 ++++++++++++++++++ 1 file changed, 590 insertions(+) create mode 100644 sources/tech/20180614 An introduction to the Tornado Python web app framework.md diff --git a/sources/tech/20180614 An introduction to the Tornado Python web app framework.md b/sources/tech/20180614 An introduction to the Tornado Python web app framework.md new file mode 100644 index 0000000000..9c9e5c9500 --- /dev/null +++ b/sources/tech/20180614 An introduction to the Tornado Python web app framework.md @@ -0,0 +1,590 @@ +[#]: collector: (lujun9972) +[#]: translator: ( ) +[#]: reviewer: ( ) +[#]: publisher: ( ) +[#]: subject: (An introduction to the Tornado Python web app framework) +[#]: via: (https://opensource.com/article/18/6/tornado-framework) +[#]: author: (Nicholas Hunt-Walker https://opensource.com/users/nhuntwalker) +[#]: url: ( ) + +An introduction to the Tornado Python web app framework +====== +In the third part in a series comparing Python frameworks, learn about Tornado, built to handle asynchronous processes. +![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/tornado.png?itok=kAa3eXIU) + +In the first two articles in this four-part series comparing different Python web frameworks, we've covered the [Pyramid][1] and [Flask][2] web frameworks. We've built the same app twice and seen the similarities and differences between a complete DIY framework and a framework with a few more batteries included. + +Now let's look at a somewhat different option: [the Tornado framework][3]. Tornado is, for the most part, as bare-bones as Flask, but with a major difference: Tornado is built specifically to handle asynchronous processes. That special sauce isn't terribly useful in the app we're building in this series, but we'll see where we can use it and how it works in a more general situation. + +Let's continue the pattern we set in the first two articles and start by tackling the setup and config. + +### Tornado startup and configuration + +If you've been following along with this series, what we do first shouldn't come as much of a surprise. + +``` +$ mkdir tornado_todo +$ cd tornado_todo +$ pipenv install --python 3.6 +$ pipenv shell +(tornado-someHash) $ pipenv install tornado +``` + +Create a `setup.py` for installing our application: + +``` +(tornado-someHash) $ touch setup.py +# setup.py +from setuptools import setup, find_packages + +requires = [ +    'tornado', +    'tornado-sqlalchemy', +    'psycopg2', +] + +setup( +    name='tornado_todo', +    version='0.0', +    description='A To-Do List built with Tornado', +    author='', +    author_email='', +    keywords='web tornado', +    packages=find_packages(), +    install_requires=requires, +    entry_points={ +        'console_scripts': [ +            'serve_app = todo:main', +        ], +    }, +) +``` + +Because Tornado doesn't require any external configuration, we can dive right into writing the Python code that'll run our application. Let's make our inner `todo` directory and fill it with the first few files we'll need. + +``` +todo/ +    __init__.py +    models.py +    views.py +``` + +Like Flask and Pyramid, Tornado has some central configuration that will go in `__init__.py`. From `tornado.web`, we'll import the `Application` object. This will handle the hookups for routing and views, including our database (when we get there) and any extra settings needed to run our Tornado app. + +``` +# __init__.py +from tornado.httpserver import HTTPServer +from tornado.options import define, options +from tornado.web import Application + +define('port', default=8888, help='port to listen on') + +def main(): +    """Construct and serve the tornado application.""" +    app = Application() +    http_server = HTTPServer(app) +    http_server.listen(options.port) +``` + +When we use the `define` function, we end up creating attributes on the `options` object. Anything that goes in the position of the first argument will be the attribute's name, and what's assigned to the `default` keyword argument will be the value of that attribute. + +As an example, if we name the attribute `potato` instead of `port`, we can access its value via `options.potato`. + +Calling `listen` on the `HTTPServer` doesn't start the server yet. We must do one more step to have a working application that can listen for requests and return responses. We need an input-output loop. Thankfully, Tornado comes with that out of the box in the form of `tornado.ioloop.IOLoop`. + +``` +# __init__.py +from tornado.httpserver import HTTPServer +from tornado.ioloop import IOLoop +from tornado.options import define, options +from tornado.web import Application + +define('port', default=8888, help='port to listen on') + +def main(): +    """Construct and serve the tornado application.""" +    app = Application() +    http_server = HTTPServer(app) +    http_server.listen(options.port) +    print('Listening on http://localhost:%i' % options.port) +    IOLoop.current().start() +``` + +I like some kind of a `print` statement somewhere that tells me when I'm serving my application, but that's me. You could do without the `print` line if you so chose. + +We begin our I/O loop with `IOLoop.current().start()`. Let's talk a little more about input, output, and asynchronicity. + +### The basics of async in Python and the I/O loop + +Allow me to preface by saying that I am absolutely, positively, surely, and securely not an expert in asynchronous programming. As with all things I write, what follows stems from the limits of my understanding of the concept. As I am human, it may be deeply, deeply flawed. + +The main concerns of an asynchronous program are: + + * How is data coming in? + * How is data going out? + * When can some procedure be left to run without consuming my full attention? + + + +Due to the [global interpreter lock][4] (GIL), Python is—by design—a [single-threaded][5] language. For every task a Python program must execute, the full attention of its thread of execution is on that task for the duration of that task. Our HTTP server is written in Python. Thus, when data (e.g., an HTTP request) is received, the server's sole focus is that incoming data. This means that, in most cases, whatever procedures need to run in handling and processing that data will completely consume your server's thread of execution, blocking other potential data from being received until your server finishes whatever it needed to do. + +In many cases this isn't too problematic; a typical web request-response cycle will take only fractions of a second. Along with that, the sockets that HTTP servers are built from can maintain a backlog of incoming requests to be handled. So, if a request comes in while that socket is handling something else, chances are it'll just wait in line a bit before being addressed. For a low to intermediate traffic site, a fraction of a second isn't that big of a deal, and you can use multiple deployed instances along with a load-balancer like [NGINX][6] to distribute traffic for the larger request loads. + +What if, however, your average response time takes more than a fraction of a second? What if you use data from the incoming request to start some long-running process like a machine-learning algorithm or some massive database query? Now, your single-threaded web server starts to accumulate an unaddressable backlog of requests, some of which will get dropped due to simply timing out. This is not an option, especially if you want your service to be seen as reliable on a regular basis. + +In comes the asynchronous Python program. It's important to keep in mind that because it's written in Python, the program is still a single-threaded process. Anything that would block execution in a synchronous program, unless specifically flagged, will still block execution in an asynchronous one. + +When it's structured correctly, however, your asynchronous Python program can "shelve" long-running tasks whenever you designate that a certain function should have the ability to do so. Your async controller can then be alerted when the shelved tasks are complete and ready to resume, managing their execution only when needed without completely blocking the handling of new input. + +That was somewhat jargony, so let's demonstrate with a human example. + +#### Bringing it home + +I often find myself trying to get multiple chores done at home with little time to do them. On a given day, that backlog of chores may look like: + + * Cook a meal (20 min. prep, 40 min. cook) + * Wash dishes (60 min.) + * Wash and dry laundry (30 min. wash, 90 min. dry per load) + * Vacuum floors (30 min.) + + + +If I were acting as a traditional, synchronous program, I'd be doing each task myself, by hand. Each task would require my full attention to complete before I could consider handling anything else, as nothing would get done without my active attention. So my sequence of execution might look like: + + 1. Focus fully on preparing and cooking the meal, including waiting around for food to just… cook (60 min.). + 2. Transfer dirty dishes to sink (65 min. elapsed). + 3. Wash all the dishes (125 min. elapsed). + 4. Start laundry with my full focus on that, including waiting around for the washing machine to finish, then transferring laundry to the dryer, and waiting for the dryer to finish (250 min. elapsed). + 5. Vacuum the floors (280 min. elapsed). + + + +That's 4 hours and 40 minutes to complete my chores from end-to-end. + +Instead of working hard, I should work smart like an asynchronous program. My home is full of machines that can do my work for me without my continuous effort. Meanwhile, I can switch my attention to what may actively need it right now. + +My execution sequence might instead look like: + + 1. Load clothes into and start the washing machine (5 min.). + 2. While the washing machine is running, prep food (25 min. elapsed). + 3. After prepping food, start cooking food (30 min. elapsed). + 4. While the food is cooking, move clothes from the washing machine into the dryer and start dryer (35 min. elapsed). + 5. While dryer is running and food is still cooking, vacuum the floors (65 min. elapsed). + 6. After vacuuming the floors, take food off the stove and load the dishwasher (70 min. elapsed). + 7. Run the dishwasher (130 min. when done). + + + +Now I'm down to 2 hours and 10 minutes. Even if I allow more time for switching between jobs (10-20 more minutes total), I'm still down to about half the time I would've spent if I'd waited to perform each task in sequential order. This is the power of structuring your program to be asynchronous. + +#### So where does the I/O loop come in? + +An asynchronous Python program works by taking in data from some external source (input) and, should the process require it, offloading that data to some external worker (output) for processing. When that external process finishes, the main Python program is alerted. The program then picks up the result of that external processing (input) and continues on its merry way. + +Whenever that data isn't actively in the hands of the main Python program, that main program is freed to work on just about anything else. This includes awaiting completely new inputs (e.g., HTTP requests) and handling the results of long-running processes (e.g., results of machine-learning algorithms, long-running database queries). The main program, while still single-threaded, becomes event-driven, triggered into action for specific occurrences handled by the program. The main worker that listens for those events and dictates how they should be handled is the I/O loop. + +We traveled a long road to get to this nugget of an explanation, I know, but what I'm hoping to communicate here is that it's not magic, nor is it some type of complex parallel processing or multi-threaded work. The global interpreter lock is still in place; any long-running process within the main program will still block anything else from happening. The program is also still single-threaded; however, by externalizing tedious work, we conserve the attention of that thread to only what it needs to be attentive to. + +This is kind of like my asynchronous chores above. When my attention is fully necessary for prepping food, that's all I'm doing. However, when I can get the stove to do work for me by cooking my food, and the dishwasher to wash my dishes, and the washing machine and dryer to handle my laundry, my attention is freed to work on other things. When I am alerted that one of my long-running tasks is finished and ready to be handled once again, if my attention is free, I can pick up the results of that task and do whatever needs to be done with it next. + +### Tornado routes and views + +Despite having gone through all the trouble of talking about async in Python, we're going to hold off on using it for a bit and first write a basic Tornado view. + +Unlike the function-based views we've seen in the Flask and Pyramid implementations, Tornado's views are all class-based. This means we'll no longer use individual, standalone functions to dictate how requests are handled. Instead, the incoming HTTP request will be caught and assigned to be an attribute of our defined class. Its methods will then handle the corresponding request types. + +Let's start with a basic view that prints "Hello, World" to the screen. Every class-based view we construct for our Tornado app must inherit from the `RequestHandler` object found in `tornado.web`. This will set up all the ground-level logic that we'll need (but don't want to write) to take in a request and construct a properly formatted HTTP response. + +``` +from tornado.web import RequestHandler + +class HelloWorld(RequestHandler): +    """Print 'Hello, world!' as the response body.""" + +    def get(self): +        """Handle a GET request for saying Hello World!.""" +        self.write("Hello, world!") +``` + +Because we're looking to handle a `GET` request, we declare (really override) the `get` method. Instead of returning anything, we provide text or a JSON-serializable object to be written to the response body with `self.write`. After that, we let the `RequestHandler` take on the rest of the work that must be done before a response can be sent. + +As it stands, this view has no actual connection to the Tornado application itself. We have to go back into `__init__.py` and update the `main` function a bit. Here's the new hotness: + +``` +# __init__.py +from tornado.httpserver import HTTPServer +from tornado.ioloop import IOLoop +from tornado.options import define, options +from tornado.web import Application +from todo.views import HelloWorld + +define('port', default=8888, help='port to listen on') + +def main(): +    """Construct and serve the tornado application.""" +    app = Application([ +        ('/', HelloWorld) +    ]) +    http_server = HTTPServer(app) +    http_server.listen(options.port) +    print('Listening on http://localhost:%i' % options.port) +    IOLoop.current().start() +``` + +#### What'd we do? + +We imported the `HelloWorld` view from the `views.py` file into `__init__.py` at the top of the script. Then we added a list of route-view pairs as the first argument to the instantiation to `Application`. Whenever we want to declare a route in our application, it must be tied to a view. You can use the same view for multiple routes if you want, but there must always be a view for every route. + +We can make sure this all works by running our app with the `serve_app` command we enabled in the `setup.py`. Check `http://localhost:8888/` and see that it says "Hello, world!" + +Of course, there's more we can and will do in this space, but let's move on to models. + +### Connecting the database + +If we want to hold onto data, we need to connect a database. Like with Flask, we'll be using a framework-specific variant of SQLAlchemy called [tornado-sqlalchemy][7]. + +Why use this instead of just the bare [SQLAlchemy][8]? Well, `tornado-sqlalchemy` has all the goodness of straightforward SQLAlchemy, so we can still declare models with a common `Base` as well as use all the column data types and relationships to which we've grown accustomed. Alongside what we already know from habit, `tornado-sqlalchemy` provides an accessible async pattern for its database-querying functionality specifically to work with Tornado's existing I/O loop. + +We set the stage by adding `tornado-sqlalchemy` and `psycopg2` to `setup.py` to the list of required packages and reinstall the package. In `models.py`, we declare our models. This step looks pretty much exactly like what we've already seen in Flask and Pyramid, so I'll skip the full-class declarations and just put up the necessaries of the `Task` model. + +``` +# this is not the complete models.py, but enough to see the differences +from tornado_sqlalchemy import declarative_base + +Base = declarative_base + +class Task(Base): +    # and so on, because literally everything's the same... +``` + +We still have to connect `tornado-sqlalchemy` to the actual application. In `__init__.py`, we'll be defining the database and integrating it into the application. + +``` +# __init__.py +from tornado.httpserver import HTTPServer +from tornado.ioloop import IOLoop +from tornado.options import define, options +from tornado.web import Application +from todo.views import HelloWorld + +# add these +import os +from tornado_sqlalchemy import make_session_factory + +define('port', default=8888, help='port to listen on') +factory = make_session_factory(os.environ.get('DATABASE_URL', '')) + +def main(): +    """Construct and serve the tornado application.""" +    app = Application([ +        ('/', HelloWorld) +    ], +        session_factory=factory +    ) +    http_server = HTTPServer(app) +    http_server.listen(options.port) +    print('Listening on http://localhost:%i' % options.port) +    IOLoop.current().start() +``` + +Much like the session factory we passed around in Pyramid, we can use `make_session_factory` to take in a database URL and produce an object whose sole purpose is to provide connections to the database for our views. We then tie it into our application by passing the newly created `factory` into the `Application` object with the `session_factory` keyword argument. + +Finally, initializing and managing the database will look the same as it did for Flask and Pyramid (i.e., separate DB management script, working with respect to the `Base` object, etc.). It'll look so similar that I'm not going to reproduce it here. + +### Revisiting views + +Hello, World is always nice for learning the basics, but we need some real, application-specific views. + +Let's start with the info view. + +``` +# views.py +import json +from tornado.web import RequestHandler + +class InfoView(RequestHandler): +    """Only allow GET requests.""" +    SUPPORTED_METHODS = ["GET"] + +    def set_default_headers(self): +        """Set the default response header to be JSON.""" +        self.set_header("Content-Type", 'application/json; charset="utf-8"') + +    def get(self): +        """List of routes for this API.""" +        routes = { +            'info': 'GET /api/v1', +            'register': 'POST /api/v1/accounts', +            'single profile detail': 'GET /api/v1/accounts/', +            'edit profile': 'PUT /api/v1/accounts/', +            'delete profile': 'DELETE /api/v1/accounts/', +            'login': 'POST /api/v1/accounts/login', +            'logout': 'GET /api/v1/accounts/logout', +            "user's tasks": 'GET /api/v1/accounts//tasks', +            "create task": 'POST /api/v1/accounts//tasks', +            "task detail": 'GET /api/v1/accounts//tasks/', +            "task update": 'PUT /api/v1/accounts//tasks/', +            "delete task": 'DELETE /api/v1/accounts//tasks/' +        } +        self.write(json.dumps(routes)) +``` + +So what changed? Let's go from the top down. + +The `SUPPORTED_METHODS` class attribute was added. This will be an iterable of only the request methods that are accepted by this view. Any other method will return a [405][9] status code. When we made the `HelloWorld` view, we didn't specify this, mostly out of laziness. Without this class attribute, this view would respond to any request trying to access the route tied to the view. + +The `set_default_headers` method is declared, which sets the default headers of the outgoing HTTP response. We declare this here to ensure that any response we send back has a `"Content-Type"` of `"application/json"`. + +We added `json.dumps(some_object)` to the argument of `self.write` because it makes it easy to construct the content for the body of the outgoing response. + +Now that's done, and we can go ahead and connect it to the home route in `__init__.py`. + +``` +# __init__.py +from tornado.httpserver import HTTPServer +from tornado.ioloop import IOLoop +from tornado.options import define, options +from tornado.web import Application +from todo.views import InfoView + +# add these +import os +from tornado_sqlalchemy import make_session_factory + +define('port', default=8888, help='port to listen on') +factory = make_session_factory(os.environ.get('DATABASE_URL', '')) + +def main(): +    """Construct and serve the tornado application.""" +    app = Application([ +        ('/', InfoView) +    ], +        session_factory=factory +    ) +    http_server = HTTPServer(app) +    http_server.listen(options.port) +    print('Listening on http://localhost:%i' % options.port) +    IOLoop.current().start() +``` + +As we know, more views and routes will need to be written. Each one will get dropped into the `Application` route listing as needed. Each will also need a `set_default_headers` method. On top of that, we'll create our `send_response`method, whose job it will be to package our response along with any custom status codes we want to set for a given response. Since each one will need both methods, we can create a base class containing them that each of our views can inherit from. That way, we have to write them only once. + +``` +# views.py +import json +from tornado.web import RequestHandler + +class BaseView(RequestHandler): +    """Base view for this application.""" + +    def set_default_headers(self): +        """Set the default response header to be JSON.""" +        self.set_header("Content-Type", 'application/json; charset="utf-8"') + +    def send_response(self, data, status=200): +        """Construct and send a JSON response with appropriate status code.""" +        self.set_status(status) +        self.write(json.dumps(data)) +``` + +For a view like the `TaskListView` we'll soon write, we'll also need a connection to the database. We'll need `tornado_sqlalchemy`'s `SessionMixin` to add a database session within every view class. We can fold that into the `BaseView` so that, by default, every view inheriting from it has access to a database session. + +``` +# views.py +import json +from tornado_sqlalchemy import SessionMixin +from tornado.web import RequestHandler + +class BaseView(RequestHandler, SessionMixin): +    """Base view for this application.""" + +    def set_default_headers(self): +        """Set the default response header to be JSON.""" +        self.set_header("Content-Type", 'application/json; charset="utf-8"') + +    def send_response(self, data, status=200): +        """Construct and send a JSON response with appropriate status code.""" +        self.set_status(status) +        self.write(json.dumps(data)) +``` + +As long as we're modifying this `BaseView` object, we should address a quirk that will come up when we consider data being posted to this API. + +When Tornado (as of v.4.5) consumes data from a client and organizes it for use in the application, it keeps all the incoming data as bytestrings. However, all the code here assumes Python 3, so the only strings that we want to work with are Unicode strings. We can add another method to this `BaseView` class whose job it will be to convert the incoming data to Unicode before using it anywhere else in the view. + +If we want to convert this data before we use it in a proper view method, we can override the view class's native `prepare` method. Its job is to run before the view method runs. If we override the `prepare` method, we can set some logic to run that'll do the bytestring-to-Unicode conversion whenever a request is received. + +``` +# views.py +import json +from tornado_sqlalchemy import SessionMixin +from tornado.web import RequestHandler + +class BaseView(RequestHandler, SessionMixin): +    """Base view for this application.""" + +    def prepare(self): +        self.form_data = { +            key: [val.decode('utf8') for val in val_list] +            for key, val_list in self.request.arguments.items() +        } + +    def set_default_headers(self): +        """Set the default response header to be JSON.""" +        self.set_header("Content-Type", 'application/json; charset="utf-8"') + +    def send_response(self, data, status=200): +        """Construct and send a JSON response with appropriate status code.""" +        self.set_status(status) +        self.write(json.dumps(data)) +``` + +If there's any data coming in, it'll be found within the `self.request.arguments` dictionary. We can access that data by key and convert its contents (always a list) to Unicode. Because this is a class-based view instead of a function-based view, we can store the modified data as an instance attribute to be used later. I called it `form_data` here, but it can just as easily be called `potato`. The point is that we can store data that has been submitted to the application. + +### Asynchronous view methods + +Now that we've built our `BaseView`, we can build the `TaskListView` that will inherit from it. + +As you can probably tell from the section heading, this is where all that talk about asynchronicity comes in. The `TaskListView` will handle `GET` requests for returning a list of tasks and `POST` requests for creating new tasks given some form data. Let's first look at the code to handle the `GET` request. + +``` +# all the previous imports +import datetime +from tornado.gen import coroutine +from tornado_sqlalchemy import as_future +from todo.models import Profile, Task + +# the BaseView is above here +class TaskListView(BaseView): +    """View for reading and adding new tasks.""" +    SUPPORTED_METHODS = ("GET", "POST",) + +    @coroutine +    def get(self, username): +        """Get all tasks for an existing user.""" +        with self.make_session() as session: +            profile = yield as_future(session.query(Profile).filter(Profile.username == username).first) +            if profile: +                tasks = [task.to_dict() for task in profile.tasks] +                self.send_response({ +                    'username': profile.username, +                    'tasks': tasks +                }) +``` + +The first major piece here is the `@coroutine` decorator, imported from `tornado.gen`. Any Python callable that has a portion that acts out of sync with the normal flow of the call stack is effectively a "co-routine"; a routine that can run alongside other routines. In the example of my household chores, pretty much every chore was a co-routine. Some were blocking routines (e.g., vacuuming the floor), but that routine simply blocked my ability to start or attend to anything else. It didn't block any of the other routines that were already set in motion from continuing. + +Tornado offers a number of ways to build an app that take advantage of co-routines, including allowing us to set locks on function calls, conditions for synchronizing asynchronous routines, and a system for manually modifying the events that control the I/O loop. + +The only way the `@coroutine` decorator is used here is to allow the `get` method to farm out the SQL query as a background process and resume once the query is complete, while not blocking the Tornado I/O loop from handling other sources of incoming data. That is all that's "asynchronous" about this implementation: out-of-band database queries. Clearly if we wanted to showcase the magic and wonder of an async web app, a To-Do List isn't the way. + +But hey, that's what we're building, so let's see how our method takes advantage of that `@coroutine` decorator. The `SessionMixin` that was, well, mixed into the `BaseView` declaration added two handy, database-aware attributes to our view class: `session` and `make_session`. They're similarly named and accomplish fairly similar goals. + +The `self.session` attribute is a session with an eye on the database. At the end of the request-response cycle, just before the view sends a response back to the client, any changes that have been made to the database are committed, and the session is closed. + +`self.make_session` is a context manager and generator, building and returning a brand new session object on the fly. That first `self.session` object still exists; `make_session` creates a new one anyway. The `make_session` generator also has baked into itself the logic for committing and closing the session it creates as soon as its context (i.e., indentation level) ends. + +If you inspect the source code, there is no difference between the type of object assigned to `self.session` and the type of object generated by `self.make_session`. The difference is in how they're managed. + +With the `make_session` context manager, the generated session belongs only to the context, beginning and ending within that context. You can open, modify, commit, and close multiple database sessions within the same view with the `make_session` context manager. + +`self.session` is much simpler, with the session already opened by the time you get to your view method and committing before the response is sent back to the client. + +Although the [read the docs snippet][10] and the [the PyPI example][11] both specify the use of the context manager, there's nothing about either the `self.session` object or the `session` generated by `self.make_session` that is inherently asynchronous. The point where we start thinking about the async behavior built into `tornado-sqlalchemy` comes when we initiate a query. + +The `tornado-sqlalchemy` package provides us with the `as_future` function. The job of `as_future` is to wrap the query constructed by the `tornado-sqlalchemy` session and yield its return value. If the view method is decorated with `@coroutine`, then using this `yield as_future(query)` pattern will now make your wrapped query an asynchronous background process. The I/O loop takes over, awaiting the return value of the query and the resolution of the `future` object created by `as_future`. + +To have access to the result from `as_future(query)`, you must `yield` from it. Otherwise, you get only an unresolved generator object and can do nothing with the query. + +Everything else in this view method is pretty much par for the course, mirroring what we've already seen in Flask and Pyramid. + +The `post` method will look fairly similar. For the sake of consistency, let's see how the `post` method looks and how it handles the `self.form_data` that was constructed with the `BaseView`. + +``` +@coroutine +def post(self, username): +    """Create a new task.""" +    with self.make_session() as session: +        profile = yield as_future(session.query(Profile).filter(Profile.username == username).first) +        if profile: +            due_date = self.form_data['due_date'][0] +            task = Task( +                name=self.form_data['name'][0], +                note=self.form_data['note'][0], +                creation_date=datetime.now(), +                due_date=datetime.strptime(due_date, '%d/%m/%Y %H:%M:%S') if due_date else None, +                completed=self.form_data['completed'][0], +                profile_id=profile.id, +                profile=profile +            ) +            session.add(task) +            self.send_response({'msg': 'posted'}, status=201) +``` + +As I said, it's about what we'd expect: + + * The same query pattern as we saw with the `get` method + * The construction of an instance of a new `Task` object, populated with data from `form_data` + * The adding (but not committing because it's handled by the context manager!) of the new `Task` object to the database session + * The sending of a response back to the client + + + +And thus we have the basis for our Tornado web app. Everything else (e.g., database management and more views for a more complete app) is effectively the same as what we've already seen in the Flask and Pyramid apps. + +### Thoughts about using the right tool for the right job + +What we're starting to see as we continue to move through these web frameworks is that they can all effectively handle the same problems. For something like this To-Do List, any framework can do the job. However, some web frameworks are more appropriate for certain jobs than other ones, depending on what "more appropriate" means for you and your needs. + +While Tornado is clearly capable of handling the same job that Pyramid or Flask can handle, to use it for an app like this is effectively a waste. It's like using a car to travel one block from home. Yes it can do the job of "travel," but short trips aren't why you choose to use a car over a bike or just your feet. + +Per the documentation, Tornado is billed as "a Python web framework and asynchronous networking library." There are few like it in the Python web framework ecosystem. If the job you're trying to accomplish requires (or would benefit significantly from) asynchronicity in any way, shape, or form, use Tornado. If your application needs to handle multiple, long-lived connections while not sacrificing much in performance, choose Tornado. If your application is many applications in one and needs to be thread-aware for the accurate handling of data, reach for Tornado. That's where it works best. + +Use your car to do "car things." Use other modes of transportation to do everything else. + +### Going forward and a little perspective check + +Speaking of using the right tool for the right job, keep in mind the scope and scale, both present and future, of your application when choosing your framework. Up to this point we've only looked at frameworks meant for small to midsized web applications. The next and final installment of this series will cover one of the most popular Python frameworks, Django, meant for big applications that might grow bigger. Again, while it technically can and will handle the To-Do List problem, keep in mind that it's not really what the framework is for. We'll still put it through its paces to show how an application can be built with it, but we have to keep in mind the intent of the framework and how that's reflected in its architecture: + + * **Flask:** Meant for small, simple projects; makes it easy for us to construct views and connect them to routes quickly; can be encapsulated in a single file without much fuss + * **Pyramid:** Meant for projects that may grow; contains a fair bit of configuration to get up and running; separate realms of application components can easily be divided and built out to arbitrary depth without losing sight of the central application + * **Tornado:** Meant for projects benefiting from precise and deliberate I/O control; allows for co-routines and easily exposes methods that can control how requests are received/responses are sent and when those operations occur + * **Django:** (As we'll see) meant for big things that may get bigger; large ecosystem of add-ons and mods; very opinionated in its configuration and management in order to keep all the disparate parts in line + + + +Whether you've been reading since the first post in this series or joined a little later, thanks for reading! Please feel free to leave questions or comments. I'll see you next time with hands full of Django. + +### Huge shout-out to the Python BDFL + +I must give credit where credit is due. Massive thanks are owed to [Guido van Rossum][12] for more than just creating my favorite programming language. + +During [PyCascades 2018][13], I was fortunate not only to give the talk this article series is based on, but also to be invited to the speakers' dinner. I got to sit next to Guido the whole night and pepper him with questions. One of those questions was how in the world async worked in Python, and he, without a bit of fuss, spent time explaining it to me in a way that I could start to grasp the concept. He later [tweeted to me][14] a spectacular resource for learning async with Python that I subsequently read three times over three months, then wrote this post. You're an awesome guy, Guido! + +-------------------------------------------------------------------------------- + +via: https://opensource.com/article/18/6/tornado-framework + +作者:[Nicholas Hunt-Walker][a] +选题:[lujun9972][b] +译者:[译者ID](https://github.com/译者ID) +校对:[校对者ID](https://github.com/校对者ID) + +本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出 + +[a]: https://opensource.com/users/nhuntwalker +[b]: https://github.com/lujun9972 +[1]: https://opensource.com/article/18/5/pyramid-framework +[2]: https://opensource.com/article/18/4/flask +[3]: https://tornado.readthedocs.io/en/stable/ +[4]: https://realpython.com/python-gil/ +[5]: https://en.wikipedia.org/wiki/Thread_(computing) +[6]: https://www.nginx.com/ +[7]: https://tornado-sqlalchemy.readthedocs.io/en/latest/ +[8]: https://www.sqlalchemy.org/ +[9]: https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#4xx_Client_errors +[10]: https://tornado-sqlalchemy.readthedocs.io/en/latest/#usage +[11]: https://pypi.org/project/tornado-sqlalchemy/#description +[12]: https://www.twitter.com/gvanrossum +[13]: https://www.pycascades.com +[14]: https://twitter.com/gvanrossum/status/956186585493458944 From 5b04538f0e9539fefe40dc3f51e5c4fb96d4efab Mon Sep 17 00:00:00 2001 From: "Xingyu.Wang" Date: Fri, 30 Nov 2018 23:50:53 +0800 Subject: [PATCH 05/12] =?UTF-8?q?=E5=BD=92=E6=A1=A3=20201811?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../20140114 Caffeinated 6.828:Lab 2 Memory Management.md | 0 ...160627 9 Best Free Video Editing Software for Linux In 2017.md | 0 ...0928 A 3-step process for making more transparent decisions.md | 0 ...or Authentication For SSH On Ubuntu 16.04 And Debian Jessie.md | 0 .../20171027 Scout out code problems with SonarQube.md | 0 ...use a here documents to write data to a file in bash script.md | 0 published/{ => 201811}/20171202 Simulating the Altair.md | 0 published/{ => 201811}/20171229 Excellent Free Roguelike Games.md | 0 .../20180101 Manage Your Games Using Lutris In Linux.md | 0 ...ng Your Own Private Registry with Docker Enterprise Edition.md | 0 published/{ => 201811}/20180127 Write Dumb Code.md | 0 .../20180215 Build a bikesharing app with Redis and Python.md | 0 ... Ditching a bunch of stuff and moving to Emacs and org-mode.md | 0 .../20180305 Getting started with Python for data science.md | 0 ...uestions DevOps job candidates should be prepared to answer.md | 0 ...403 17 Ways To Check Size Of Physical Memory (RAM) In Linux.md | 0 ...09 5 steps to building a cloud that meets your users- needs.md | 0 .../20180409 How to create LaTeX documents with Emacs.md | 0 .../20180417 How To Browse Stack Overflow From Terminal.md | 0 .../20180417 What developers need to know about security.md | 0 ...s to improve collaboration between developers and designers.md | 0 ...180530 How To Add, Enable And Disable A Repository In Linux.md | 0 ...plete Sed Command Guide [Explained with Practical Examples].md | 0 ...Bjarne Stroustrup warns of dangerous future plans for his C.md | 0 published/{ => 201811}/20180626 8 great pytest plugins.md | 0 ...lay Store And Enable ARM (libhoudini) Support, The Easy Way.md | 0 .../20180716 How To Find The Mounted Filesystem Type In Linux.md | 0 .../20180723 Setting Up a Timer with systemd in Linux.md | 0 ... lightweight OS for your next home project - Opensource.com.md | 0 .../20180801 5 of the Best Linux Games to Play in 2018.md | 0 ...LI Tool To Easily Manage Multiple Software Development Kits.md | 0 ...20180807 5 reasons the i3 window manager makes Linux better.md | 0 ...0 How To Quickly Serve Files And Folders Over HTTP In Linux.md | 0 ...o End Sync Support For All Filesystems Except Ext4 on Linux.md | 0 ...0180814 Top Linux developers- recommended programming books.md | 0 ...0816 An introduction to the Django Python web app framework.md | 0 ...To Disable Ads In Terminal Welcome Message In Ubuntu Server.md | 0 ...in- Encrypted Open Source Note Taking And To-Do Application.md | 0 .../{ => 201811}/20180827 Top 10 Raspberry Pi blogs to follow.md | 0 .../{ => 201811}/20180831 Test containers with Python and Conu.md | 0 ...eshot - A Simple, Yet Powerful Feature-rich Screenshot Tool.md | 0 .../20180903 A Cross-platform High-quality GIF Encoder.md | 0 .../20180905 How To Run MS-DOS Games And Programs In Linux.md | 0 .../20180907 6 open source tools for writing a book.md | 0 published/{ => 201811}/20180907 6.828 lab tools guide.md | 0 published/{ => 201811}/20180911 Tools Used in 6.828.md | 0 .../20180914 Convert files at the command line with Pandoc.md | 0 ...unt- A New Bounty Hunting Platform for Open Source Software.md | 0 .../20180928 Using Grails with jQuery and DataTables.md | 0 .../20180928 What containers can teach us about DevOps.md | 0 ...1001 Turn your book into a website and an ePub using Pandoc.md | 0 ...20181002 4 open source invoicing tools for small businesses.md | 0 ...Hartman Explains How the Kernel Community Is Securing Linux.md | 0 ...Functional programming in Python- Immutable data structures.md | 0 ...ol To Record Your Terminal And Generate Animated Gif Images.md | 0 ...t for Servers - Enter Open Source, Goodbye Proprietary UEFI.md | 0 published/{ => 201811}/20181008 3 areas to drive DevOps change.md | 0 ...08 KeeWeb - An Open Source, Cross Platform Password Manager.md | 0 ...008 Play Windows games on Fedora with Steam Play and Proton.md | 0 .../20181010 5 alerting and visualization tools for sysadmins.md | 0 ... An introduction to using tcpdump at the Linux command line.md | 0 .../20181014 How Lisp Became God-s Own Programming Language.md | 0 ...ices on Boot in Linux Using chkconfig and systemctl Command.md | 0 ... Kali Linux- What You Must Know Before Using it - FOSS Post.md | 0 ...sing the web with Min, a minimalist open source web browser.md | 0 ... An Alternative NTP Client And Server For Unix-like Systems.md | 0 ...20181017 Design faster web pages, part 2- Image replacement.md | 0 ...o Determine Which System Manager Is Running On Linux System.md | 0 .../20181019 Edit your videos with Pitivi on Fedora.md | 0 .../20181019 How to use Pandoc to produce a research paper.md | 0 .../20181019 What is an SRE and how does it relate to DevOps.md | 0 ...20181022 5 tips for choosing the right open source database.md | 0 .../20181022 How to set up WordPress on a Raspberry Pi.md | 0 ...th functional programming in Python using the toolz library.md | 0 ...0181024 4 cool new projects to try in COPR for October 2018.md | 0 ...81024 Get organized at the Linux command line with Calcurse.md | 0 ...nitoring database health and behavior- Which metrics matter.md | 0 .../{ => 201811}/20181025 Understanding Linux Links- Part 2.md | 0 ...20181025 What breaks our systems- A taxonomy of black swans.md | 0 published/{ => 201811}/20181026 An Overview of Android Pie.md | 0 ...ate Plumber - Writing Linux Pipes With Instant Live Preview.md | 0 ...181027 Design faster web pages, part 3- Font and CSS tweaks.md | 0 .../{ => 201811}/20181029 4 open source Android email clients.md | 0 ...29 Machine learning with Python- Essential hacks and tricks.md | 0 ... Find Out The Installed Packages Came From Which Repository.md | 0 ...30 How To Analyze And Explore The Contents Of Docker Images.md | 0 ... 8 creepy commands that haunt the terminal - Opensource.com.md | 0 ...RS- A new tool for gathering Kubernetes resource statistics.md | 0 ...reate A Bootable Linux USB Drive From Windows OS 7,8 and 10.md | 0 .../20181105 CPod- An Open Source, Cross-platform Podcast App.md | 0 .../20181105 Commandline quick tips- How to locate a file.md | 0 ...ducing pydbgen- A random dataframe-database table generator.md | 0 .../20181105 Revisiting the Unix philosophy in 2018.md | 0 .../20181105 Some Good Alternatives To ‘du- Command.md | 0 .../20181107 Gitbase- Exploring git repos with SQL.md | 0 ...To Find The Execution Time Of A Command Or Process In Linux.md | 0 published/{ => 201811}/20181108 Choosing a printer for Linux.md | 0 ...0181108 The Difference Between more, less And most Commands.md | 0 published/{ => 201811}/20181109 7 reasons I love open source.md | 0 published/{ => 201811}/20181113 4 tips for learning Golang.md | 0 ...1113 The alias And unalias Commands Explained With Examples.md | 0 ... What you need to know about the GPL Cooperation Commitment.md | 0 ...edText - A Free Encrypted Notepad To Save Your Notes Online.md | 0 .../20181115 How to install a device driver on Linux.md | 0 published/{ => 201811}/20181116 Akash Angle- How do you Fedora.md | 0 .../20181117 How to enter single user mode in SUSE 12 Linux.md | 0 .../20181119 How To Customize Bash Prompt In Linux.md | 0 ...0181120 How To Change GDM Login Screen Background In Ubuntu.md | 0 ...use multiple programming languages without losing your mind.md | 0 109 files changed, 0 insertions(+), 0 deletions(-) rename published/{ => 201811}/20140114 Caffeinated 6.828:Lab 2 Memory Management.md (100%) rename published/{ => 201811}/20160627 9 Best Free Video Editing Software for Linux In 2017.md (100%) rename published/{ => 201811}/20170928 A 3-step process for making more transparent decisions.md (100%) rename published/{ => 201811}/20171002 Three Alternatives for Enabling Two Factor Authentication For SSH On Ubuntu 16.04 And Debian Jessie.md (100%) rename published/{ => 201811}/20171027 Scout out code problems with SonarQube.md (100%) rename published/{ => 201811}/20171116 How to use a here documents to write data to a file in bash script.md (100%) rename published/{ => 201811}/20171202 Simulating the Altair.md (100%) rename published/{ => 201811}/20171229 Excellent Free Roguelike Games.md (100%) rename published/{ => 201811}/20180101 Manage Your Games Using Lutris In Linux.md (100%) rename published/{ => 201811}/20180110 Using Your Own Private Registry with Docker Enterprise Edition.md (100%) rename published/{ => 201811}/20180127 Write Dumb Code.md (100%) rename published/{ => 201811}/20180215 Build a bikesharing app with Redis and Python.md (100%) rename published/{ => 201811}/20180227 Emacs -1- Ditching a bunch of stuff and moving to Emacs and org-mode.md (100%) rename published/{ => 201811}/20180305 Getting started with Python for data science.md (100%) rename published/{ => 201811}/20180308 20 questions DevOps job candidates should be prepared to answer.md (100%) rename published/{ => 201811}/20180403 17 Ways To Check Size Of Physical Memory (RAM) In Linux.md (100%) rename published/{ => 201811}/20180409 5 steps to building a cloud that meets your users- needs.md (100%) rename published/{ => 201811}/20180409 How to create LaTeX documents with Emacs.md (100%) rename published/{ => 201811}/20180417 How To Browse Stack Overflow From Terminal.md (100%) rename published/{ => 201811}/20180417 What developers need to know about security.md (100%) rename published/{ => 201811}/20180502 9 ways to improve collaboration between developers and designers.md (100%) rename published/{ => 201811}/20180530 How To Add, Enable And Disable A Repository In Linux.md (100%) rename published/{ => 201811}/20180615 Complete Sed Command Guide [Explained with Practical Examples].md (100%) rename published/{ => 201811}/20180618 What-s all the C Plus Fuss- Bjarne Stroustrup warns of dangerous future plans for his C.md (100%) rename published/{ => 201811}/20180626 8 great pytest plugins.md (100%) rename published/{ => 201811}/20180709 Anbox- How To Install Google Play Store And Enable ARM (libhoudini) Support, The Easy Way.md (100%) rename published/{ => 201811}/20180716 How To Find The Mounted Filesystem Type In Linux.md (100%) rename published/{ => 201811}/20180723 Setting Up a Timer with systemd in Linux.md (100%) rename published/{ => 201811}/20180730 A single-user, lightweight OS for your next home project - Opensource.com.md (100%) rename published/{ => 201811}/20180801 5 of the Best Linux Games to Play in 2018.md (100%) rename published/{ => 201811}/20180803 SDKMAN - A CLI Tool To Easily Manage Multiple Software Development Kits.md (100%) rename published/{ => 201811}/20180807 5 reasons the i3 window manager makes Linux better.md (100%) rename published/{ => 201811}/20180810 How To Quickly Serve Files And Folders Over HTTP In Linux.md (100%) rename published/{ => 201811}/20180811 Dropbox To End Sync Support For All Filesystems Except Ext4 on Linux.md (100%) rename published/{ => 201811}/20180814 Top Linux developers- recommended programming books.md (100%) rename published/{ => 201811}/20180816 An introduction to the Django Python web app framework.md (100%) rename published/{ => 201811}/20180820 How To Disable Ads In Terminal Welcome Message In Ubuntu Server.md (100%) rename published/{ => 201811}/20180824 Joplin- Encrypted Open Source Note Taking And To-Do Application.md (100%) rename published/{ => 201811}/20180827 Top 10 Raspberry Pi blogs to follow.md (100%) rename published/{ => 201811}/20180831 Test containers with Python and Conu.md (100%) rename published/{ => 201811}/20180901 Flameshot - A Simple, Yet Powerful Feature-rich Screenshot Tool.md (100%) rename published/{ => 201811}/20180903 A Cross-platform High-quality GIF Encoder.md (100%) rename published/{ => 201811}/20180905 How To Run MS-DOS Games And Programs In Linux.md (100%) rename published/{ => 201811}/20180907 6 open source tools for writing a book.md (100%) rename published/{ => 201811}/20180907 6.828 lab tools guide.md (100%) rename published/{ => 201811}/20180911 Tools Used in 6.828.md (100%) rename published/{ => 201811}/20180914 Convert files at the command line with Pandoc.md (100%) rename published/{ => 201811}/20180921 IssueHunt- A New Bounty Hunting Platform for Open Source Software.md (100%) rename published/{ => 201811}/20180928 Using Grails with jQuery and DataTables.md (100%) rename published/{ => 201811}/20180928 What containers can teach us about DevOps.md (100%) rename published/{ => 201811}/20181001 Turn your book into a website and an ePub using Pandoc.md (100%) rename published/{ => 201811}/20181002 4 open source invoicing tools for small businesses.md (100%) rename published/{ => 201811}/20181002 Greg Kroah-Hartman Explains How the Kernel Community Is Securing Linux.md (100%) rename published/{ => 201811}/20181004 Functional programming in Python- Immutable data structures.md (100%) rename published/{ => 201811}/20181005 Terminalizer - A Tool To Record Your Terminal And Generate Animated Gif Images.md (100%) rename published/{ => 201811}/20181006 LinuxBoot for Servers - Enter Open Source, Goodbye Proprietary UEFI.md (100%) rename published/{ => 201811}/20181008 3 areas to drive DevOps change.md (100%) rename published/{ => 201811}/20181008 KeeWeb - An Open Source, Cross Platform Password Manager.md (100%) rename published/{ => 201811}/20181008 Play Windows games on Fedora with Steam Play and Proton.md (100%) rename published/{ => 201811}/20181010 5 alerting and visualization tools for sysadmins.md (100%) rename published/{ => 201811}/20181010 An introduction to using tcpdump at the Linux command line.md (100%) rename published/{ => 201811}/20181014 How Lisp Became God-s Own Programming Language.md (100%) rename published/{ => 201811}/20181015 How to Enable or Disable Services on Boot in Linux Using chkconfig and systemctl Command.md (100%) rename published/{ => 201811}/20181015 Kali Linux- What You Must Know Before Using it - FOSS Post.md (100%) rename published/{ => 201811}/20181017 Browsing the web with Min, a minimalist open source web browser.md (100%) rename published/{ => 201811}/20181017 Chrony - An Alternative NTP Client And Server For Unix-like Systems.md (100%) rename published/{ => 201811}/20181017 Design faster web pages, part 2- Image replacement.md (100%) rename published/{ => 201811}/20181017 How To Determine Which System Manager Is Running On Linux System.md (100%) rename published/{ => 201811}/20181019 Edit your videos with Pitivi on Fedora.md (100%) rename published/{ => 201811}/20181019 How to use Pandoc to produce a research paper.md (100%) rename published/{ => 201811}/20181019 What is an SRE and how does it relate to DevOps.md (100%) rename published/{ => 201811}/20181022 5 tips for choosing the right open source database.md (100%) rename published/{ => 201811}/20181022 How to set up WordPress on a Raspberry Pi.md (100%) rename published/{ => 201811}/20181023 Getting started with functional programming in Python using the toolz library.md (100%) rename published/{ => 201811}/20181024 4 cool new projects to try in COPR for October 2018.md (100%) rename published/{ => 201811}/20181024 Get organized at the Linux command line with Calcurse.md (100%) rename published/{ => 201811}/20181025 Monitoring database health and behavior- Which metrics matter.md (100%) rename published/{ => 201811}/20181025 Understanding Linux Links- Part 2.md (100%) rename published/{ => 201811}/20181025 What breaks our systems- A taxonomy of black swans.md (100%) rename published/{ => 201811}/20181026 An Overview of Android Pie.md (100%) rename published/{ => 201811}/20181026 Ultimate Plumber - Writing Linux Pipes With Instant Live Preview.md (100%) rename published/{ => 201811}/20181027 Design faster web pages, part 3- Font and CSS tweaks.md (100%) rename published/{ => 201811}/20181029 4 open source Android email clients.md (100%) rename published/{ => 201811}/20181029 Machine learning with Python- Essential hacks and tricks.md (100%) rename published/{ => 201811}/20181030 How Do We Find Out The Installed Packages Came From Which Repository.md (100%) rename published/{ => 201811}/20181030 How To Analyze And Explore The Contents Of Docker Images.md (100%) rename published/{ => 201811}/20181031 8 creepy commands that haunt the terminal - Opensource.com.md (100%) rename published/{ => 201811}/20181101 KRS- A new tool for gathering Kubernetes resource statistics.md (100%) rename published/{ => 201811}/20181102 How To Create A Bootable Linux USB Drive From Windows OS 7,8 and 10.md (100%) rename published/{ => 201811}/20181105 CPod- An Open Source, Cross-platform Podcast App.md (100%) rename published/{ => 201811}/20181105 Commandline quick tips- How to locate a file.md (100%) rename published/{ => 201811}/20181105 Introducing pydbgen- A random dataframe-database table generator.md (100%) rename published/{ => 201811}/20181105 Revisiting the Unix philosophy in 2018.md (100%) rename published/{ => 201811}/20181105 Some Good Alternatives To ‘du- Command.md (100%) rename published/{ => 201811}/20181107 Gitbase- Exploring git repos with SQL.md (100%) rename published/{ => 201811}/20181107 How To Find The Execution Time Of A Command Or Process In Linux.md (100%) rename published/{ => 201811}/20181108 Choosing a printer for Linux.md (100%) rename published/{ => 201811}/20181108 The Difference Between more, less And most Commands.md (100%) rename published/{ => 201811}/20181109 7 reasons I love open source.md (100%) rename published/{ => 201811}/20181113 4 tips for learning Golang.md (100%) rename published/{ => 201811}/20181113 The alias And unalias Commands Explained With Examples.md (100%) rename published/{ => 201811}/20181113 What you need to know about the GPL Cooperation Commitment.md (100%) rename published/{ => 201811}/20181114 ProtectedText - A Free Encrypted Notepad To Save Your Notes Online.md (100%) rename published/{ => 201811}/20181115 How to install a device driver on Linux.md (100%) rename published/{ => 201811}/20181116 Akash Angle- How do you Fedora.md (100%) rename published/{ => 201811}/20181117 How to enter single user mode in SUSE 12 Linux.md (100%) rename published/{ => 201811}/20181119 How To Customize Bash Prompt In Linux.md (100%) rename published/{ => 201811}/20181120 How To Change GDM Login Screen Background In Ubuntu.md (100%) rename published/{ => 201811}/20181126 How to use multiple programming languages without losing your mind.md (100%) diff --git a/published/20140114 Caffeinated 6.828:Lab 2 Memory Management.md b/published/201811/20140114 Caffeinated 6.828:Lab 2 Memory Management.md similarity index 100% rename from published/20140114 Caffeinated 6.828:Lab 2 Memory Management.md rename to published/201811/20140114 Caffeinated 6.828:Lab 2 Memory Management.md diff --git a/published/20160627 9 Best Free Video Editing Software for Linux In 2017.md b/published/201811/20160627 9 Best Free Video Editing Software for Linux In 2017.md similarity index 100% rename from published/20160627 9 Best Free Video Editing Software for Linux In 2017.md rename to published/201811/20160627 9 Best Free Video Editing Software for Linux In 2017.md diff --git a/published/20170928 A 3-step process for making more transparent decisions.md b/published/201811/20170928 A 3-step process for making more transparent decisions.md similarity index 100% rename from published/20170928 A 3-step process for making more transparent decisions.md rename to published/201811/20170928 A 3-step process for making more transparent decisions.md diff --git a/published/20171002 Three Alternatives for Enabling Two Factor Authentication For SSH On Ubuntu 16.04 And Debian Jessie.md b/published/201811/20171002 Three Alternatives for Enabling Two Factor Authentication For SSH On Ubuntu 16.04 And Debian Jessie.md similarity index 100% rename from published/20171002 Three Alternatives for Enabling Two Factor Authentication For SSH On Ubuntu 16.04 And Debian Jessie.md rename to published/201811/20171002 Three Alternatives for Enabling Two Factor Authentication For SSH On Ubuntu 16.04 And Debian Jessie.md diff --git a/published/20171027 Scout out code problems with SonarQube.md b/published/201811/20171027 Scout out code problems with SonarQube.md similarity index 100% rename from published/20171027 Scout out code problems with SonarQube.md rename to published/201811/20171027 Scout out code problems with SonarQube.md diff --git a/published/20171116 How to use a here documents to write data to a file in bash script.md b/published/201811/20171116 How to use a here documents to write data to a file in bash script.md similarity index 100% rename from published/20171116 How to use a here documents to write data to a file in bash script.md rename to published/201811/20171116 How to use a here documents to write data to a file in bash script.md diff --git a/published/20171202 Simulating the Altair.md b/published/201811/20171202 Simulating the Altair.md similarity index 100% rename from published/20171202 Simulating the Altair.md rename to published/201811/20171202 Simulating the Altair.md diff --git a/published/20171229 Excellent Free Roguelike Games.md b/published/201811/20171229 Excellent Free Roguelike Games.md similarity index 100% rename from published/20171229 Excellent Free Roguelike Games.md rename to published/201811/20171229 Excellent Free Roguelike Games.md diff --git a/published/20180101 Manage Your Games Using Lutris In Linux.md b/published/201811/20180101 Manage Your Games Using Lutris In Linux.md similarity index 100% rename from published/20180101 Manage Your Games Using Lutris In Linux.md rename to published/201811/20180101 Manage Your Games Using Lutris In Linux.md diff --git a/published/20180110 Using Your Own Private Registry with Docker Enterprise Edition.md b/published/201811/20180110 Using Your Own Private Registry with Docker Enterprise Edition.md similarity index 100% rename from published/20180110 Using Your Own Private Registry with Docker Enterprise Edition.md rename to published/201811/20180110 Using Your Own Private Registry with Docker Enterprise Edition.md diff --git a/published/20180127 Write Dumb Code.md b/published/201811/20180127 Write Dumb Code.md similarity index 100% rename from published/20180127 Write Dumb Code.md rename to published/201811/20180127 Write Dumb Code.md diff --git a/published/20180215 Build a bikesharing app with Redis and Python.md b/published/201811/20180215 Build a bikesharing app with Redis and Python.md similarity index 100% rename from published/20180215 Build a bikesharing app with Redis and Python.md rename to published/201811/20180215 Build a bikesharing app with Redis and Python.md diff --git a/published/20180227 Emacs -1- Ditching a bunch of stuff and moving to Emacs and org-mode.md b/published/201811/20180227 Emacs -1- Ditching a bunch of stuff and moving to Emacs and org-mode.md similarity index 100% rename from published/20180227 Emacs -1- Ditching a bunch of stuff and moving to Emacs and org-mode.md rename to published/201811/20180227 Emacs -1- Ditching a bunch of stuff and moving to Emacs and org-mode.md diff --git a/published/20180305 Getting started with Python for data science.md b/published/201811/20180305 Getting started with Python for data science.md similarity index 100% rename from published/20180305 Getting started with Python for data science.md rename to published/201811/20180305 Getting started with Python for data science.md diff --git a/published/20180308 20 questions DevOps job candidates should be prepared to answer.md b/published/201811/20180308 20 questions DevOps job candidates should be prepared to answer.md similarity index 100% rename from published/20180308 20 questions DevOps job candidates should be prepared to answer.md rename to published/201811/20180308 20 questions DevOps job candidates should be prepared to answer.md diff --git a/published/20180403 17 Ways To Check Size Of Physical Memory (RAM) In Linux.md b/published/201811/20180403 17 Ways To Check Size Of Physical Memory (RAM) In Linux.md similarity index 100% rename from published/20180403 17 Ways To Check Size Of Physical Memory (RAM) In Linux.md rename to published/201811/20180403 17 Ways To Check Size Of Physical Memory (RAM) In Linux.md diff --git a/published/20180409 5 steps to building a cloud that meets your users- needs.md b/published/201811/20180409 5 steps to building a cloud that meets your users- needs.md similarity index 100% rename from published/20180409 5 steps to building a cloud that meets your users- needs.md rename to published/201811/20180409 5 steps to building a cloud that meets your users- needs.md diff --git a/published/20180409 How to create LaTeX documents with Emacs.md b/published/201811/20180409 How to create LaTeX documents with Emacs.md similarity index 100% rename from published/20180409 How to create LaTeX documents with Emacs.md rename to published/201811/20180409 How to create LaTeX documents with Emacs.md diff --git a/published/20180417 How To Browse Stack Overflow From Terminal.md b/published/201811/20180417 How To Browse Stack Overflow From Terminal.md similarity index 100% rename from published/20180417 How To Browse Stack Overflow From Terminal.md rename to published/201811/20180417 How To Browse Stack Overflow From Terminal.md diff --git a/published/20180417 What developers need to know about security.md b/published/201811/20180417 What developers need to know about security.md similarity index 100% rename from published/20180417 What developers need to know about security.md rename to published/201811/20180417 What developers need to know about security.md diff --git a/published/20180502 9 ways to improve collaboration between developers and designers.md b/published/201811/20180502 9 ways to improve collaboration between developers and designers.md similarity index 100% rename from published/20180502 9 ways to improve collaboration between developers and designers.md rename to published/201811/20180502 9 ways to improve collaboration between developers and designers.md diff --git a/published/20180530 How To Add, Enable And Disable A Repository In Linux.md b/published/201811/20180530 How To Add, Enable And Disable A Repository In Linux.md similarity index 100% rename from published/20180530 How To Add, Enable And Disable A Repository In Linux.md rename to published/201811/20180530 How To Add, Enable And Disable A Repository In Linux.md diff --git a/published/20180615 Complete Sed Command Guide [Explained with Practical Examples].md b/published/201811/20180615 Complete Sed Command Guide [Explained with Practical Examples].md similarity index 100% rename from published/20180615 Complete Sed Command Guide [Explained with Practical Examples].md rename to published/201811/20180615 Complete Sed Command Guide [Explained with Practical Examples].md diff --git a/published/20180618 What-s all the C Plus Fuss- Bjarne Stroustrup warns of dangerous future plans for his C.md b/published/201811/20180618 What-s all the C Plus Fuss- Bjarne Stroustrup warns of dangerous future plans for his C.md similarity index 100% rename from published/20180618 What-s all the C Plus Fuss- Bjarne Stroustrup warns of dangerous future plans for his C.md rename to published/201811/20180618 What-s all the C Plus Fuss- Bjarne Stroustrup warns of dangerous future plans for his C.md diff --git a/published/20180626 8 great pytest plugins.md b/published/201811/20180626 8 great pytest plugins.md similarity index 100% rename from published/20180626 8 great pytest plugins.md rename to published/201811/20180626 8 great pytest plugins.md diff --git a/published/20180709 Anbox- How To Install Google Play Store And Enable ARM (libhoudini) Support, The Easy Way.md b/published/201811/20180709 Anbox- How To Install Google Play Store And Enable ARM (libhoudini) Support, The Easy Way.md similarity index 100% rename from published/20180709 Anbox- How To Install Google Play Store And Enable ARM (libhoudini) Support, The Easy Way.md rename to published/201811/20180709 Anbox- How To Install Google Play Store And Enable ARM (libhoudini) Support, The Easy Way.md diff --git a/published/20180716 How To Find The Mounted Filesystem Type In Linux.md b/published/201811/20180716 How To Find The Mounted Filesystem Type In Linux.md similarity index 100% rename from published/20180716 How To Find The Mounted Filesystem Type In Linux.md rename to published/201811/20180716 How To Find The Mounted Filesystem Type In Linux.md diff --git a/published/20180723 Setting Up a Timer with systemd in Linux.md b/published/201811/20180723 Setting Up a Timer with systemd in Linux.md similarity index 100% rename from published/20180723 Setting Up a Timer with systemd in Linux.md rename to published/201811/20180723 Setting Up a Timer with systemd in Linux.md diff --git a/published/20180730 A single-user, lightweight OS for your next home project - Opensource.com.md b/published/201811/20180730 A single-user, lightweight OS for your next home project - Opensource.com.md similarity index 100% rename from published/20180730 A single-user, lightweight OS for your next home project - Opensource.com.md rename to published/201811/20180730 A single-user, lightweight OS for your next home project - Opensource.com.md diff --git a/published/20180801 5 of the Best Linux Games to Play in 2018.md b/published/201811/20180801 5 of the Best Linux Games to Play in 2018.md similarity index 100% rename from published/20180801 5 of the Best Linux Games to Play in 2018.md rename to published/201811/20180801 5 of the Best Linux Games to Play in 2018.md diff --git a/published/20180803 SDKMAN - A CLI Tool To Easily Manage Multiple Software Development Kits.md b/published/201811/20180803 SDKMAN - A CLI Tool To Easily Manage Multiple Software Development Kits.md similarity index 100% rename from published/20180803 SDKMAN - A CLI Tool To Easily Manage Multiple Software Development Kits.md rename to published/201811/20180803 SDKMAN - A CLI Tool To Easily Manage Multiple Software Development Kits.md diff --git a/published/20180807 5 reasons the i3 window manager makes Linux better.md b/published/201811/20180807 5 reasons the i3 window manager makes Linux better.md similarity index 100% rename from published/20180807 5 reasons the i3 window manager makes Linux better.md rename to published/201811/20180807 5 reasons the i3 window manager makes Linux better.md diff --git a/published/20180810 How To Quickly Serve Files And Folders Over HTTP In Linux.md b/published/201811/20180810 How To Quickly Serve Files And Folders Over HTTP In Linux.md similarity index 100% rename from published/20180810 How To Quickly Serve Files And Folders Over HTTP In Linux.md rename to published/201811/20180810 How To Quickly Serve Files And Folders Over HTTP In Linux.md diff --git a/published/20180811 Dropbox To End Sync Support For All Filesystems Except Ext4 on Linux.md b/published/201811/20180811 Dropbox To End Sync Support For All Filesystems Except Ext4 on Linux.md similarity index 100% rename from published/20180811 Dropbox To End Sync Support For All Filesystems Except Ext4 on Linux.md rename to published/201811/20180811 Dropbox To End Sync Support For All Filesystems Except Ext4 on Linux.md diff --git a/published/20180814 Top Linux developers- recommended programming books.md b/published/201811/20180814 Top Linux developers- recommended programming books.md similarity index 100% rename from published/20180814 Top Linux developers- recommended programming books.md rename to published/201811/20180814 Top Linux developers- recommended programming books.md diff --git a/published/20180816 An introduction to the Django Python web app framework.md b/published/201811/20180816 An introduction to the Django Python web app framework.md similarity index 100% rename from published/20180816 An introduction to the Django Python web app framework.md rename to published/201811/20180816 An introduction to the Django Python web app framework.md diff --git a/published/20180820 How To Disable Ads In Terminal Welcome Message In Ubuntu Server.md b/published/201811/20180820 How To Disable Ads In Terminal Welcome Message In Ubuntu Server.md similarity index 100% rename from published/20180820 How To Disable Ads In Terminal Welcome Message In Ubuntu Server.md rename to published/201811/20180820 How To Disable Ads In Terminal Welcome Message In Ubuntu Server.md diff --git a/published/20180824 Joplin- Encrypted Open Source Note Taking And To-Do Application.md b/published/201811/20180824 Joplin- Encrypted Open Source Note Taking And To-Do Application.md similarity index 100% rename from published/20180824 Joplin- Encrypted Open Source Note Taking And To-Do Application.md rename to published/201811/20180824 Joplin- Encrypted Open Source Note Taking And To-Do Application.md diff --git a/published/20180827 Top 10 Raspberry Pi blogs to follow.md b/published/201811/20180827 Top 10 Raspberry Pi blogs to follow.md similarity index 100% rename from published/20180827 Top 10 Raspberry Pi blogs to follow.md rename to published/201811/20180827 Top 10 Raspberry Pi blogs to follow.md diff --git a/published/20180831 Test containers with Python and Conu.md b/published/201811/20180831 Test containers with Python and Conu.md similarity index 100% rename from published/20180831 Test containers with Python and Conu.md rename to published/201811/20180831 Test containers with Python and Conu.md diff --git a/published/20180901 Flameshot - A Simple, Yet Powerful Feature-rich Screenshot Tool.md b/published/201811/20180901 Flameshot - A Simple, Yet Powerful Feature-rich Screenshot Tool.md similarity index 100% rename from published/20180901 Flameshot - A Simple, Yet Powerful Feature-rich Screenshot Tool.md rename to published/201811/20180901 Flameshot - A Simple, Yet Powerful Feature-rich Screenshot Tool.md diff --git a/published/20180903 A Cross-platform High-quality GIF Encoder.md b/published/201811/20180903 A Cross-platform High-quality GIF Encoder.md similarity index 100% rename from published/20180903 A Cross-platform High-quality GIF Encoder.md rename to published/201811/20180903 A Cross-platform High-quality GIF Encoder.md diff --git a/published/20180905 How To Run MS-DOS Games And Programs In Linux.md b/published/201811/20180905 How To Run MS-DOS Games And Programs In Linux.md similarity index 100% rename from published/20180905 How To Run MS-DOS Games And Programs In Linux.md rename to published/201811/20180905 How To Run MS-DOS Games And Programs In Linux.md diff --git a/published/20180907 6 open source tools for writing a book.md b/published/201811/20180907 6 open source tools for writing a book.md similarity index 100% rename from published/20180907 6 open source tools for writing a book.md rename to published/201811/20180907 6 open source tools for writing a book.md diff --git a/published/20180907 6.828 lab tools guide.md b/published/201811/20180907 6.828 lab tools guide.md similarity index 100% rename from published/20180907 6.828 lab tools guide.md rename to published/201811/20180907 6.828 lab tools guide.md diff --git a/published/20180911 Tools Used in 6.828.md b/published/201811/20180911 Tools Used in 6.828.md similarity index 100% rename from published/20180911 Tools Used in 6.828.md rename to published/201811/20180911 Tools Used in 6.828.md diff --git a/published/20180914 Convert files at the command line with Pandoc.md b/published/201811/20180914 Convert files at the command line with Pandoc.md similarity index 100% rename from published/20180914 Convert files at the command line with Pandoc.md rename to published/201811/20180914 Convert files at the command line with Pandoc.md diff --git a/published/20180921 IssueHunt- A New Bounty Hunting Platform for Open Source Software.md b/published/201811/20180921 IssueHunt- A New Bounty Hunting Platform for Open Source Software.md similarity index 100% rename from published/20180921 IssueHunt- A New Bounty Hunting Platform for Open Source Software.md rename to published/201811/20180921 IssueHunt- A New Bounty Hunting Platform for Open Source Software.md diff --git a/published/20180928 Using Grails with jQuery and DataTables.md b/published/201811/20180928 Using Grails with jQuery and DataTables.md similarity index 100% rename from published/20180928 Using Grails with jQuery and DataTables.md rename to published/201811/20180928 Using Grails with jQuery and DataTables.md diff --git a/published/20180928 What containers can teach us about DevOps.md b/published/201811/20180928 What containers can teach us about DevOps.md similarity index 100% rename from published/20180928 What containers can teach us about DevOps.md rename to published/201811/20180928 What containers can teach us about DevOps.md diff --git a/published/20181001 Turn your book into a website and an ePub using Pandoc.md b/published/201811/20181001 Turn your book into a website and an ePub using Pandoc.md similarity index 100% rename from published/20181001 Turn your book into a website and an ePub using Pandoc.md rename to published/201811/20181001 Turn your book into a website and an ePub using Pandoc.md diff --git a/published/20181002 4 open source invoicing tools for small businesses.md b/published/201811/20181002 4 open source invoicing tools for small businesses.md similarity index 100% rename from published/20181002 4 open source invoicing tools for small businesses.md rename to published/201811/20181002 4 open source invoicing tools for small businesses.md diff --git a/published/20181002 Greg Kroah-Hartman Explains How the Kernel Community Is Securing Linux.md b/published/201811/20181002 Greg Kroah-Hartman Explains How the Kernel Community Is Securing Linux.md similarity index 100% rename from published/20181002 Greg Kroah-Hartman Explains How the Kernel Community Is Securing Linux.md rename to published/201811/20181002 Greg Kroah-Hartman Explains How the Kernel Community Is Securing Linux.md diff --git a/published/20181004 Functional programming in Python- Immutable data structures.md b/published/201811/20181004 Functional programming in Python- Immutable data structures.md similarity index 100% rename from published/20181004 Functional programming in Python- Immutable data structures.md rename to published/201811/20181004 Functional programming in Python- Immutable data structures.md diff --git a/published/20181005 Terminalizer - A Tool To Record Your Terminal And Generate Animated Gif Images.md b/published/201811/20181005 Terminalizer - A Tool To Record Your Terminal And Generate Animated Gif Images.md similarity index 100% rename from published/20181005 Terminalizer - A Tool To Record Your Terminal And Generate Animated Gif Images.md rename to published/201811/20181005 Terminalizer - A Tool To Record Your Terminal And Generate Animated Gif Images.md diff --git a/published/20181006 LinuxBoot for Servers - Enter Open Source, Goodbye Proprietary UEFI.md b/published/201811/20181006 LinuxBoot for Servers - Enter Open Source, Goodbye Proprietary UEFI.md similarity index 100% rename from published/20181006 LinuxBoot for Servers - Enter Open Source, Goodbye Proprietary UEFI.md rename to published/201811/20181006 LinuxBoot for Servers - Enter Open Source, Goodbye Proprietary UEFI.md diff --git a/published/20181008 3 areas to drive DevOps change.md b/published/201811/20181008 3 areas to drive DevOps change.md similarity index 100% rename from published/20181008 3 areas to drive DevOps change.md rename to published/201811/20181008 3 areas to drive DevOps change.md diff --git a/published/20181008 KeeWeb - An Open Source, Cross Platform Password Manager.md b/published/201811/20181008 KeeWeb - An Open Source, Cross Platform Password Manager.md similarity index 100% rename from published/20181008 KeeWeb - An Open Source, Cross Platform Password Manager.md rename to published/201811/20181008 KeeWeb - An Open Source, Cross Platform Password Manager.md diff --git a/published/20181008 Play Windows games on Fedora with Steam Play and Proton.md b/published/201811/20181008 Play Windows games on Fedora with Steam Play and Proton.md similarity index 100% rename from published/20181008 Play Windows games on Fedora with Steam Play and Proton.md rename to published/201811/20181008 Play Windows games on Fedora with Steam Play and Proton.md diff --git a/published/20181010 5 alerting and visualization tools for sysadmins.md b/published/201811/20181010 5 alerting and visualization tools for sysadmins.md similarity index 100% rename from published/20181010 5 alerting and visualization tools for sysadmins.md rename to published/201811/20181010 5 alerting and visualization tools for sysadmins.md diff --git a/published/20181010 An introduction to using tcpdump at the Linux command line.md b/published/201811/20181010 An introduction to using tcpdump at the Linux command line.md similarity index 100% rename from published/20181010 An introduction to using tcpdump at the Linux command line.md rename to published/201811/20181010 An introduction to using tcpdump at the Linux command line.md diff --git a/published/20181014 How Lisp Became God-s Own Programming Language.md b/published/201811/20181014 How Lisp Became God-s Own Programming Language.md similarity index 100% rename from published/20181014 How Lisp Became God-s Own Programming Language.md rename to published/201811/20181014 How Lisp Became God-s Own Programming Language.md diff --git a/published/20181015 How to Enable or Disable Services on Boot in Linux Using chkconfig and systemctl Command.md b/published/201811/20181015 How to Enable or Disable Services on Boot in Linux Using chkconfig and systemctl Command.md similarity index 100% rename from published/20181015 How to Enable or Disable Services on Boot in Linux Using chkconfig and systemctl Command.md rename to published/201811/20181015 How to Enable or Disable Services on Boot in Linux Using chkconfig and systemctl Command.md diff --git a/published/20181015 Kali Linux- What You Must Know Before Using it - FOSS Post.md b/published/201811/20181015 Kali Linux- What You Must Know Before Using it - FOSS Post.md similarity index 100% rename from published/20181015 Kali Linux- What You Must Know Before Using it - FOSS Post.md rename to published/201811/20181015 Kali Linux- What You Must Know Before Using it - FOSS Post.md diff --git a/published/20181017 Browsing the web with Min, a minimalist open source web browser.md b/published/201811/20181017 Browsing the web with Min, a minimalist open source web browser.md similarity index 100% rename from published/20181017 Browsing the web with Min, a minimalist open source web browser.md rename to published/201811/20181017 Browsing the web with Min, a minimalist open source web browser.md diff --git a/published/20181017 Chrony - An Alternative NTP Client And Server For Unix-like Systems.md b/published/201811/20181017 Chrony - An Alternative NTP Client And Server For Unix-like Systems.md similarity index 100% rename from published/20181017 Chrony - An Alternative NTP Client And Server For Unix-like Systems.md rename to published/201811/20181017 Chrony - An Alternative NTP Client And Server For Unix-like Systems.md diff --git a/published/20181017 Design faster web pages, part 2- Image replacement.md b/published/201811/20181017 Design faster web pages, part 2- Image replacement.md similarity index 100% rename from published/20181017 Design faster web pages, part 2- Image replacement.md rename to published/201811/20181017 Design faster web pages, part 2- Image replacement.md diff --git a/published/20181017 How To Determine Which System Manager Is Running On Linux System.md b/published/201811/20181017 How To Determine Which System Manager Is Running On Linux System.md similarity index 100% rename from published/20181017 How To Determine Which System Manager Is Running On Linux System.md rename to published/201811/20181017 How To Determine Which System Manager Is Running On Linux System.md diff --git a/published/20181019 Edit your videos with Pitivi on Fedora.md b/published/201811/20181019 Edit your videos with Pitivi on Fedora.md similarity index 100% rename from published/20181019 Edit your videos with Pitivi on Fedora.md rename to published/201811/20181019 Edit your videos with Pitivi on Fedora.md diff --git a/published/20181019 How to use Pandoc to produce a research paper.md b/published/201811/20181019 How to use Pandoc to produce a research paper.md similarity index 100% rename from published/20181019 How to use Pandoc to produce a research paper.md rename to published/201811/20181019 How to use Pandoc to produce a research paper.md diff --git a/published/20181019 What is an SRE and how does it relate to DevOps.md b/published/201811/20181019 What is an SRE and how does it relate to DevOps.md similarity index 100% rename from published/20181019 What is an SRE and how does it relate to DevOps.md rename to published/201811/20181019 What is an SRE and how does it relate to DevOps.md diff --git a/published/20181022 5 tips for choosing the right open source database.md b/published/201811/20181022 5 tips for choosing the right open source database.md similarity index 100% rename from published/20181022 5 tips for choosing the right open source database.md rename to published/201811/20181022 5 tips for choosing the right open source database.md diff --git a/published/20181022 How to set up WordPress on a Raspberry Pi.md b/published/201811/20181022 How to set up WordPress on a Raspberry Pi.md similarity index 100% rename from published/20181022 How to set up WordPress on a Raspberry Pi.md rename to published/201811/20181022 How to set up WordPress on a Raspberry Pi.md diff --git a/published/20181023 Getting started with functional programming in Python using the toolz library.md b/published/201811/20181023 Getting started with functional programming in Python using the toolz library.md similarity index 100% rename from published/20181023 Getting started with functional programming in Python using the toolz library.md rename to published/201811/20181023 Getting started with functional programming in Python using the toolz library.md diff --git a/published/20181024 4 cool new projects to try in COPR for October 2018.md b/published/201811/20181024 4 cool new projects to try in COPR for October 2018.md similarity index 100% rename from published/20181024 4 cool new projects to try in COPR for October 2018.md rename to published/201811/20181024 4 cool new projects to try in COPR for October 2018.md diff --git a/published/20181024 Get organized at the Linux command line with Calcurse.md b/published/201811/20181024 Get organized at the Linux command line with Calcurse.md similarity index 100% rename from published/20181024 Get organized at the Linux command line with Calcurse.md rename to published/201811/20181024 Get organized at the Linux command line with Calcurse.md diff --git a/published/20181025 Monitoring database health and behavior- Which metrics matter.md b/published/201811/20181025 Monitoring database health and behavior- Which metrics matter.md similarity index 100% rename from published/20181025 Monitoring database health and behavior- Which metrics matter.md rename to published/201811/20181025 Monitoring database health and behavior- Which metrics matter.md diff --git a/published/20181025 Understanding Linux Links- Part 2.md b/published/201811/20181025 Understanding Linux Links- Part 2.md similarity index 100% rename from published/20181025 Understanding Linux Links- Part 2.md rename to published/201811/20181025 Understanding Linux Links- Part 2.md diff --git a/published/20181025 What breaks our systems- A taxonomy of black swans.md b/published/201811/20181025 What breaks our systems- A taxonomy of black swans.md similarity index 100% rename from published/20181025 What breaks our systems- A taxonomy of black swans.md rename to published/201811/20181025 What breaks our systems- A taxonomy of black swans.md diff --git a/published/20181026 An Overview of Android Pie.md b/published/201811/20181026 An Overview of Android Pie.md similarity index 100% rename from published/20181026 An Overview of Android Pie.md rename to published/201811/20181026 An Overview of Android Pie.md diff --git a/published/20181026 Ultimate Plumber - Writing Linux Pipes With Instant Live Preview.md b/published/201811/20181026 Ultimate Plumber - Writing Linux Pipes With Instant Live Preview.md similarity index 100% rename from published/20181026 Ultimate Plumber - Writing Linux Pipes With Instant Live Preview.md rename to published/201811/20181026 Ultimate Plumber - Writing Linux Pipes With Instant Live Preview.md diff --git a/published/20181027 Design faster web pages, part 3- Font and CSS tweaks.md b/published/201811/20181027 Design faster web pages, part 3- Font and CSS tweaks.md similarity index 100% rename from published/20181027 Design faster web pages, part 3- Font and CSS tweaks.md rename to published/201811/20181027 Design faster web pages, part 3- Font and CSS tweaks.md diff --git a/published/20181029 4 open source Android email clients.md b/published/201811/20181029 4 open source Android email clients.md similarity index 100% rename from published/20181029 4 open source Android email clients.md rename to published/201811/20181029 4 open source Android email clients.md diff --git a/published/20181029 Machine learning with Python- Essential hacks and tricks.md b/published/201811/20181029 Machine learning with Python- Essential hacks and tricks.md similarity index 100% rename from published/20181029 Machine learning with Python- Essential hacks and tricks.md rename to published/201811/20181029 Machine learning with Python- Essential hacks and tricks.md diff --git a/published/20181030 How Do We Find Out The Installed Packages Came From Which Repository.md b/published/201811/20181030 How Do We Find Out The Installed Packages Came From Which Repository.md similarity index 100% rename from published/20181030 How Do We Find Out The Installed Packages Came From Which Repository.md rename to published/201811/20181030 How Do We Find Out The Installed Packages Came From Which Repository.md diff --git a/published/20181030 How To Analyze And Explore The Contents Of Docker Images.md b/published/201811/20181030 How To Analyze And Explore The Contents Of Docker Images.md similarity index 100% rename from published/20181030 How To Analyze And Explore The Contents Of Docker Images.md rename to published/201811/20181030 How To Analyze And Explore The Contents Of Docker Images.md diff --git a/published/20181031 8 creepy commands that haunt the terminal - Opensource.com.md b/published/201811/20181031 8 creepy commands that haunt the terminal - Opensource.com.md similarity index 100% rename from published/20181031 8 creepy commands that haunt the terminal - Opensource.com.md rename to published/201811/20181031 8 creepy commands that haunt the terminal - Opensource.com.md diff --git a/published/20181101 KRS- A new tool for gathering Kubernetes resource statistics.md b/published/201811/20181101 KRS- A new tool for gathering Kubernetes resource statistics.md similarity index 100% rename from published/20181101 KRS- A new tool for gathering Kubernetes resource statistics.md rename to published/201811/20181101 KRS- A new tool for gathering Kubernetes resource statistics.md diff --git a/published/20181102 How To Create A Bootable Linux USB Drive From Windows OS 7,8 and 10.md b/published/201811/20181102 How To Create A Bootable Linux USB Drive From Windows OS 7,8 and 10.md similarity index 100% rename from published/20181102 How To Create A Bootable Linux USB Drive From Windows OS 7,8 and 10.md rename to published/201811/20181102 How To Create A Bootable Linux USB Drive From Windows OS 7,8 and 10.md diff --git a/published/20181105 CPod- An Open Source, Cross-platform Podcast App.md b/published/201811/20181105 CPod- An Open Source, Cross-platform Podcast App.md similarity index 100% rename from published/20181105 CPod- An Open Source, Cross-platform Podcast App.md rename to published/201811/20181105 CPod- An Open Source, Cross-platform Podcast App.md diff --git a/published/20181105 Commandline quick tips- How to locate a file.md b/published/201811/20181105 Commandline quick tips- How to locate a file.md similarity index 100% rename from published/20181105 Commandline quick tips- How to locate a file.md rename to published/201811/20181105 Commandline quick tips- How to locate a file.md diff --git a/published/20181105 Introducing pydbgen- A random dataframe-database table generator.md b/published/201811/20181105 Introducing pydbgen- A random dataframe-database table generator.md similarity index 100% rename from published/20181105 Introducing pydbgen- A random dataframe-database table generator.md rename to published/201811/20181105 Introducing pydbgen- A random dataframe-database table generator.md diff --git a/published/20181105 Revisiting the Unix philosophy in 2018.md b/published/201811/20181105 Revisiting the Unix philosophy in 2018.md similarity index 100% rename from published/20181105 Revisiting the Unix philosophy in 2018.md rename to published/201811/20181105 Revisiting the Unix philosophy in 2018.md diff --git a/published/20181105 Some Good Alternatives To ‘du- Command.md b/published/201811/20181105 Some Good Alternatives To ‘du- Command.md similarity index 100% rename from published/20181105 Some Good Alternatives To ‘du- Command.md rename to published/201811/20181105 Some Good Alternatives To ‘du- Command.md diff --git a/published/20181107 Gitbase- Exploring git repos with SQL.md b/published/201811/20181107 Gitbase- Exploring git repos with SQL.md similarity index 100% rename from published/20181107 Gitbase- Exploring git repos with SQL.md rename to published/201811/20181107 Gitbase- Exploring git repos with SQL.md diff --git a/published/20181107 How To Find The Execution Time Of A Command Or Process In Linux.md b/published/201811/20181107 How To Find The Execution Time Of A Command Or Process In Linux.md similarity index 100% rename from published/20181107 How To Find The Execution Time Of A Command Or Process In Linux.md rename to published/201811/20181107 How To Find The Execution Time Of A Command Or Process In Linux.md diff --git a/published/20181108 Choosing a printer for Linux.md b/published/201811/20181108 Choosing a printer for Linux.md similarity index 100% rename from published/20181108 Choosing a printer for Linux.md rename to published/201811/20181108 Choosing a printer for Linux.md diff --git a/published/20181108 The Difference Between more, less And most Commands.md b/published/201811/20181108 The Difference Between more, less And most Commands.md similarity index 100% rename from published/20181108 The Difference Between more, less And most Commands.md rename to published/201811/20181108 The Difference Between more, less And most Commands.md diff --git a/published/20181109 7 reasons I love open source.md b/published/201811/20181109 7 reasons I love open source.md similarity index 100% rename from published/20181109 7 reasons I love open source.md rename to published/201811/20181109 7 reasons I love open source.md diff --git a/published/20181113 4 tips for learning Golang.md b/published/201811/20181113 4 tips for learning Golang.md similarity index 100% rename from published/20181113 4 tips for learning Golang.md rename to published/201811/20181113 4 tips for learning Golang.md diff --git a/published/20181113 The alias And unalias Commands Explained With Examples.md b/published/201811/20181113 The alias And unalias Commands Explained With Examples.md similarity index 100% rename from published/20181113 The alias And unalias Commands Explained With Examples.md rename to published/201811/20181113 The alias And unalias Commands Explained With Examples.md diff --git a/published/20181113 What you need to know about the GPL Cooperation Commitment.md b/published/201811/20181113 What you need to know about the GPL Cooperation Commitment.md similarity index 100% rename from published/20181113 What you need to know about the GPL Cooperation Commitment.md rename to published/201811/20181113 What you need to know about the GPL Cooperation Commitment.md diff --git a/published/20181114 ProtectedText - A Free Encrypted Notepad To Save Your Notes Online.md b/published/201811/20181114 ProtectedText - A Free Encrypted Notepad To Save Your Notes Online.md similarity index 100% rename from published/20181114 ProtectedText - A Free Encrypted Notepad To Save Your Notes Online.md rename to published/201811/20181114 ProtectedText - A Free Encrypted Notepad To Save Your Notes Online.md diff --git a/published/20181115 How to install a device driver on Linux.md b/published/201811/20181115 How to install a device driver on Linux.md similarity index 100% rename from published/20181115 How to install a device driver on Linux.md rename to published/201811/20181115 How to install a device driver on Linux.md diff --git a/published/20181116 Akash Angle- How do you Fedora.md b/published/201811/20181116 Akash Angle- How do you Fedora.md similarity index 100% rename from published/20181116 Akash Angle- How do you Fedora.md rename to published/201811/20181116 Akash Angle- How do you Fedora.md diff --git a/published/20181117 How to enter single user mode in SUSE 12 Linux.md b/published/201811/20181117 How to enter single user mode in SUSE 12 Linux.md similarity index 100% rename from published/20181117 How to enter single user mode in SUSE 12 Linux.md rename to published/201811/20181117 How to enter single user mode in SUSE 12 Linux.md diff --git a/published/20181119 How To Customize Bash Prompt In Linux.md b/published/201811/20181119 How To Customize Bash Prompt In Linux.md similarity index 100% rename from published/20181119 How To Customize Bash Prompt In Linux.md rename to published/201811/20181119 How To Customize Bash Prompt In Linux.md diff --git a/published/20181120 How To Change GDM Login Screen Background In Ubuntu.md b/published/201811/20181120 How To Change GDM Login Screen Background In Ubuntu.md similarity index 100% rename from published/20181120 How To Change GDM Login Screen Background In Ubuntu.md rename to published/201811/20181120 How To Change GDM Login Screen Background In Ubuntu.md diff --git a/published/20181126 How to use multiple programming languages without losing your mind.md b/published/201811/20181126 How to use multiple programming languages without losing your mind.md similarity index 100% rename from published/20181126 How to use multiple programming languages without losing your mind.md rename to published/201811/20181126 How to use multiple programming languages without losing your mind.md From 5c970470ebab454b792745a38d184a5c2ebb3bcd Mon Sep 17 00:00:00 2001 From: DarkSun Date: Fri, 30 Nov 2018 23:51:41 +0800 Subject: [PATCH 06/12] Delete status.json --- build/status/status.json | 2121 -------------------------------------- 1 file changed, 2121 deletions(-) delete mode 100644 build/status/status.json diff --git a/build/status/status.json b/build/status/status.json deleted file mode 100644 index da99c7d874..0000000000 --- a/build/status/status.json +++ /dev/null @@ -1,2121 +0,0 @@ -{ - "translating": [ - { - "file": "sources/talk/20180904 Why schools of the future are open.md", - "time": "2018-11-06", - "user": "hkurj" - }, - { - "file": "sources/talk/20170921 The Rise and Rise of JSON.md", - "time": "2018-11-02", - "user": "thecyanbird" - }, - { - "file": "sources/talk/20180412 A new approach to security instrumentation.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20181029 How I organize my knowledge as a Software Engineer.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20181116 Akash Angle- How do you Fedora.md", - "time": "2018-11-22", - "user": "geekpi" - }, - { - "file": "sources/tech/20180523 How to dual-boot Linux and Windows.md", - "time": "2018-11-08", - "user": "Auk7F7" - }, - { - "file": "sources/tech/20171108 Continuous infrastructure- The other CI.md", - "time": "2018-11-24", - "user": "Jamkr" - }, - { - "file": "sources/tech/20180725 Build an interactive CLI with Node.js.md", - "time": "2018-10-29", - "user": "chenliang" - }, - { - "file": "sources/tech/20180727 How to analyze your system with perf and Python.md", - "time": "2018-11-03", - "user": "erlinux" - }, - { - "file": "sources/tech/20180417 How To Browse Stack Overflow From Terminal.md", - "time": "2018-11-21", - "user": "geekpi" - }, - { - "file": "sources/tech/20180806 GPaste Is A Great Clipboard Manager For Gnome Shell.md", - "time": "2018-11-23", - "user": "geekpi" - }, - { - "file": "sources/tech/20180131 For your first HTML code lets help Batman write a love letter.md", - "time": "2018-11-07", - "user": "MjSeven" - }, - { - "file": "sources/tech/20181004 4 Must-Have Tools for Monitoring Linux.md", - "time": "2018-11-02", - "user": "way-ww" - }, - { - "file": "sources/tech/20181105 How to manage storage on Linux with LVM.md", - "time": "2018-11-20", - "user": "ziang" - }, - { - "file": "sources/tech/20180707 Version Control Before Git with CVS.md", - "time": "2018-11-19", - "user": "runningwater" - }, - { - "file": "sources/tech/20181008 Taking notes with Laverna, a web-based information organizer.md", - "time": "2018-10-30", - "user": "ChenYi" - }, - { - "file": "sources/tech/20181011 Exploring the Linux kernel- The secrets of Kconfig-kbuild.md", - "time": "2018-10-27", - "user": "leemeans" - }, - { - "file": "sources/tech/20171202 Easily control delivery of your Python applications to millions of Linux users with Snapcraft.md", - "time": "2018-10-30", - "user": "David Chen" - }, - { - "file": "sources/tech/20181102 Create a containerized machine learning model.md", - "time": "2018-11-07", - "user": "suncle" - }, - { - "file": "sources/tech/20181119 9 obscure Python libraries for data science.md", - "time": "2018-11-23", - "user": "heguangzhi" - }, - { - "file": "sources/tech/20181115 3 best practices for continuous integration and deployment.md", - "time": "2018-11-19", - "user": "Leon Chi" - }, - { - "file": "sources/tech/20181120 How To Change GDM Login Screen Background In Ubuntu.md", - "time": "2018-11-23", - "user": "guevaraya" - } - ], - "unselected": [ - { - "file": "sources/talk/20170908 Betting on the Web.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20170911 What every software engineer should know about search.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20180109 How Mycroft used WordPress and GitHub to improve its documentation.md", - "time": "2018-01-11", - "user": "darksun" - }, - { - "file": "sources/talk/20181003 13 tools to measure DevOps success.md", - "time": "2018-10-08", - "user": "darksun" - }, - { - "file": "sources/talk/20180719 Finding Jobs in Software.md", - "time": "2018-11-20", - "user": "darksun" - }, - { - "file": "sources/talk/20180124 Security Chaos Engineering- A new paradigm for cybersecurity.md", - "time": "2018-01-26", - "user": "darksun" - }, - { - "file": "sources/talk/20171119 The Ruby Story.md", - "time": "2018-10-25", - "user": "darksun" - }, - { - "file": "sources/talk/20180201 6 pivotal moments in open source history.md", - "time": "2018-02-04", - "user": "Ezio" - }, - { - "file": "sources/talk/20180206 Building Slack for the Linux community and adopting snaps.md", - "time": "2018-02-08", - "user": "darksun" - }, - { - "file": "sources/talk/20180206 UQDS- A software-development process that puts quality first.md", - "time": "2018-02-08", - "user": "darksun" - }, - { - "file": "sources/talk/20180207 Why Mainframes Aren-t Going Away Any Time Soon.md", - "time": "2018-02-09", - "user": "darksun" - }, - { - "file": "sources/talk/20180208 Gathering project requirements using the Open Decision Framework.md", - "time": "2018-02-11", - "user": "darksun" - }, - { - "file": "sources/talk/20180209 Arch Anywhere Is Dead, Long Live Anarchy Linux.md", - "time": "2018-02-11", - "user": "darksun" - }, - { - "file": "sources/talk/20180209 How writing can change your career for the better, even if you don-t identify as a writer.md", - "time": "2018-10-24", - "user": "lctt-bot" - }, - { - "file": "sources/talk/20180209 Why an involved user community makes for better software.md", - "time": "2018-02-12", - "user": "darksun" - }, - { - "file": "sources/talk/20180214 Can anonymity and accountability coexist.md", - "time": "2018-02-14", - "user": "DarkSun" - }, - { - "file": "sources/talk/20180220 4 considerations when naming software development projects.md", - "time": "2018-02-24", - "user": "darksun" - }, - { - "file": "sources/talk/20180221 3 warning flags of DevOps metrics.md", - "time": "2018-03-06", - "user": "darksun" - }, - { - "file": "sources/talk/20180222 3 reasons to say -no- in DevOps.md", - "time": "2018-02-22", - "user": "darksun" - }, - { - "file": "sources/talk/20180223 Why culture is the most important issue in a DevOps transformation.md", - "time": "2018-03-01", - "user": "darksun" - }, - { - "file": "sources/talk/20180227 Emacs -1- Ditching a bunch of stuff and moving to Emacs and org-mode.md", - "time": "2018-03-01", - "user": "darksun" - }, - { - "file": "sources/talk/20180301 How to hire the right DevOps talent.md", - "time": "2018-03-06", - "user": "darksun" - }, - { - "file": "sources/talk/20180302 Beyond metrics- How to operate as team on today-s open source project.md", - "time": "2018-03-07", - "user": "darksun" - }, - { - "file": "sources/talk/20180303 4 meetup ideas- Make your data open.md", - "time": "2018-03-07", - "user": "darksun" - }, - { - "file": "sources/talk/20180314 How to apply systems thinking in DevOps.md", - "time": "2018-03-20", - "user": "darksun" - }, - { - "file": "sources/talk/20180314 Pi Day- 12 fun facts and ways to celebrate.md", - "time": "2018-03-20", - "user": "darksun" - }, - { - "file": "sources/talk/20180315 6 ways a thriving community will help your project succeed.md", - "time": "2018-03-20", - "user": "darksun" - }, - { - "file": "sources/talk/20180315 Lessons Learned from Growing an Open Source Project Too Fast.md", - "time": "2018-06-13", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20180316 How to avoid humiliating newcomers- A guide for advanced developers.md", - "time": "2018-03-20", - "user": "darksun" - }, - { - "file": "sources/talk/20180319 6 common questions about agile development practices for teams.md", - "time": "2018-03-22", - "user": "darksun" - }, - { - "file": "sources/talk/20180321 8 tips for better agile retrospective meetings.md", - "time": "2018-03-22", - "user": "darksun" - }, - { - "file": "sources/talk/20180323 7 steps to DevOps hiring success.md", - "time": "2018-03-26", - "user": "darksun" - }, - { - "file": "sources/talk/20180117 How technology changes the rules for doing agile.md", - "time": "2018-11-11", - "user": "lctt-bot" - }, - { - "file": "sources/talk/20180330 Meet OpenAuto, an Android Auto emulator for Raspberry Pi.md", - "time": "2018-04-03", - "user": "darksun" - }, - { - "file": "sources/talk/20180404 Is the term DevSecOps necessary.md", - "time": "2018-04-09", - "user": "darksun" - }, - { - "file": "sources/talk/20180405 Rethinking -ownership- across the organization.md", - "time": "2018-04-09", - "user": "darksun" - }, - { - "file": "sources/talk/20171007 The Most Important Database You-ve Never Heard of.md", - "time": "2018-10-25", - "user": "darksun" - }, - { - "file": "sources/talk/20180410 Microservices Explained.md", - "time": "2018-09-28", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20180412 Management, from coordination to collaboration.md", - "time": "2018-04-16", - "user": "darksun" - }, - { - "file": "sources/talk/20180416 For project safety back up your people, not just your data.md", - "time": "2018-04-17", - "user": "darksun" - }, - { - "file": "sources/talk/20180417 How to develop the FOSS leaders of the future.md", - "time": "2018-04-18", - "user": "darksun" - }, - { - "file": "sources/talk/20171030 Why I love technical debt.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20180418 Is DevOps compatible with part-time community teams.md", - "time": "2018-05-31", - "user": "darksun" - }, - { - "file": "sources/talk/20180419 3 tips for organizing your open source project-s workflow on GitHub.md", - "time": "2018-09-28", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20180419 5 guiding principles you should know before you design a microservice.md", - "time": "2018-04-23", - "user": "darksun" - }, - { - "file": "sources/talk/20180420 What You Don-t Know About Linux Open Source Could Be Costing to More Than You Think.md", - "time": "2018-04-23", - "user": "darksun" - }, - { - "file": "sources/talk/20180424 There-s a Server in Every Serverless Platform.md", - "time": "2018-04-26", - "user": "darksun" - }, - { - "file": "sources/talk/20170928 The Lineage of Man.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20180504 How a university network assistant used Linux in the 90s.md", - "time": "2018-05-14", - "user": "darksun" - }, - { - "file": "sources/talk/20180508 Person with diabetes finds open source and builds her own medical device.md", - "time": "2018-05-10", - "user": "darksun" - }, - { - "file": "sources/talk/20180623 The IBM 029 Card Punch.md", - "time": "2018-10-24", - "user": "darksun" - }, - { - "file": "sources/talk/20180604 10 principles of resilience for women in tech.md", - "time": "2018-06-06", - "user": "darksun" - }, - { - "file": "sources/talk/20180128 Getting Linux Jobs.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20180613 AI Is Coming to Edge Computing Devices.md", - "time": "2018-06-19", - "user": "darksun" - }, - { - "file": "sources/talk/20180619 A summer reading list for open organization enthusiasts.md", - "time": "2018-06-21", - "user": "darksun" - }, - { - "file": "sources/talk/20180622 7 tips for promoting your project and community on Twitter.md", - "time": "2018-06-28", - "user": "darksun" - }, - { - "file": "sources/talk/20180703 What Game of Thrones can teach us about open innovation.md", - "time": "2018-07-05", - "user": "darksun" - }, - { - "file": "sources/talk/20180704 Comparing Twine and Ren-Py for creating interactive fiction.md", - "time": "2018-07-06", - "user": "darksun" - }, - { - "file": "sources/talk/20180705 New Training Options Address Demand for Blockchain Skills.md", - "time": "2018-07-06", - "user": "darksun" - }, - { - "file": "sources/talk/20180216 Q4OS Makes Linux Easy for Everyone.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20180713 What-s the difference between a fork and a distribution.md", - "time": "2018-07-16", - "user": "darksun" - }, - { - "file": "sources/talk/20180724 Open Source Certification- Preparing for the Exam.md", - "time": "2018-07-26", - "user": "darksun" - }, - { - "file": "sources/talk/20171222 10 keys to quick game development.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20180726 Tech jargon- The good, the bad, and the ugly.md", - "time": "2018-07-30", - "user": "darksun" - }, - { - "file": "sources/talk/20180731 How to be the lazy sysadmin.md", - "time": "2018-08-02", - "user": "darksun" - }, - { - "file": "sources/talk/20180802 Design thinking as a way of life.md", - "time": "2018-08-06", - "user": "darksun" - }, - { - "file": "sources/talk/20180802 How blockchain will influence open source.md", - "time": "2018-08-03", - "user": "darksun" - }, - { - "file": "sources/talk/20180807 Becoming a successful programmer in an underrepresented community.md", - "time": "2018-08-09", - "user": "darksun" - }, - { - "file": "sources/talk/20180807 Building more trustful teams in four steps.md", - "time": "2018-08-09", - "user": "darksun" - }, - { - "file": "sources/talk/20171229 Important Papers- Codd and the Relational Model.md", - "time": "2018-10-25", - "user": "darksun" - }, - { - "file": "sources/talk/20180808 3 tips for moving your team to a microservices architecture.md", - "time": "2018-08-10", - "user": "darksun" - }, - { - "file": "sources/talk/20180809 How do tools affect culture.md", - "time": "2018-08-10", - "user": "darksun" - }, - { - "file": "sources/talk/20180620 3 pitfalls everyone should avoid with hybrid multi-cloud, part 2.md", - "time": "2018-08-12", - "user": "darksun" - }, - { - "file": "sources/talk/20180717 Tips for Success with Open Source Certification.md", - "time": "2018-07-24", - "user": "darksun" - }, - { - "file": "sources/talk/20180816 Debian Turns 25- Here are Some Interesting Facts About Debian Linux.md", - "time": "2018-08-17", - "user": "darksun" - }, - { - "file": "sources/talk/20180104 How Creative Commons benefits artists and big business.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20180817 OERu makes a college education affordable.md", - "time": "2018-08-19", - "user": "darksun" - }, - { - "file": "sources/talk/20171114 Why pair writing helps improve documentation.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20140412 My Lisp Experiences and the Development of GNU Emacs.md", - "time": "2018-09-28", - "user": "zhousiyu325" - }, - { - "file": "sources/talk/20171115 Why and How to Set an Open Source Strategy.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20180826 How to Install and Use FreeDOS on VirtualBox.md", - "time": "2018-08-28", - "user": "darksun" - }, - { - "file": "sources/talk/20180511 Looking at the Lispy side of Perl.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20180904 How blockchain can complement open source.md", - "time": "2018-09-05", - "user": "darksun" - }, - { - "file": "sources/talk/20180527 Whatever Happened to the Semantic Web.md", - "time": "2018-10-25", - "user": "darksun" - }, - { - "file": "sources/talk/20180906 DevOps- The consequences of blame.md", - "time": "2018-09-10", - "user": "darksun" - }, - { - "file": "sources/talk/20180724 Why moving all your workloads to the cloud is a bad idea.md", - "time": "2018-09-28", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20181009 4 best practices for giving open source code feedback.md", - "time": "2018-10-11", - "user": "darksun" - }, - { - "file": "sources/talk/20171128 The politics of the Linux desktop.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20180917 How gaming turned me into a coder.md", - "time": "2018-09-18", - "user": "darksun" - }, - { - "file": "sources/talk/20180919 5 ways DevSecOps changes security.md", - "time": "2018-09-21", - "user": "darksun" - }, - { - "file": "sources/talk/20180112 in which the cost of structured data is reduced.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20181009 GCC- Optimizing Linux, the Internet, and Everything.md", - "time": "2018-10-11", - "user": "darksun" - }, - { - "file": "sources/talk/20180920 Building a Secure Ecosystem for Node.js.md", - "time": "2018-09-21", - "user": "darksun" - }, - { - "file": "sources/talk/20181010 Talk over text- Conversational interface design and usability.md", - "time": "2018-10-12", - "user": "darksun" - }, - { - "file": "sources/talk/20181011 How to level up your organization-s security expertise.md", - "time": "2018-10-15", - "user": "darksun" - }, - { - "file": "sources/talk/20181018 Think global- How to overcome cultural communication challenges.md", - "time": "2018-10-19", - "user": "darksun" - }, - { - "file": "sources/talk/20171107 How to Monetize an Open Source Project.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20180925 Troubleshooting Node.js Issues with llnode.md", - "time": "2018-10-09", - "user": "darksun" - }, - { - "file": "sources/talk/20171116 Why is collaboration so difficult.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20181004 Interview With Peter Ganten, CEO of Univention GmbH.md", - "time": "2018-10-09", - "user": "darksun" - }, - { - "file": "sources/talk/20181017 We already have nice things, and other reasons not to write in-house ops tools.md", - "time": "2018-10-19", - "user": "darksun" - }, - { - "file": "sources/talk/20171129 Inside AGL Familiar Open Source Components Ease Learning Curve.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20171221 Changing how we use Slack solved our transparency and silo problems.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20171222 18 Cyber-Security Trends Organizations Need to Brace for in 2018.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20180104 How allowing myself to be vulnerable made me a better leader.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20180111 The open organization and inner sourcing movements can share knowledge.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20180131 How to write a really great resume that actually gets you hired.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20180209 A review of Virtual Labs virtualization solutions for MOOCs - WebLog Pro Olivier Berger.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20180223 Plasma Mobile Could Give Life to a Mobile Linux Experience.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20180328 What NASA Has Been Doing About Open Science.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20180403 3 pitfalls everyone should avoid with hybrid multicloud.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20180620 Anatomy of a perfect pull request.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20180625 8 reasons to use the Xfce Linux desktop environment.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20180629 Reflecting on the GPLv3 license for its 11th anniversary.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20180701 How to migrate to the world of Linux from Windows.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20180705 5 Reasons Open Source Certification Matters More Than Ever.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20180706 Robolinux Lets You Easily Run Linux and Windows Without Dual Booting.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20180711 Becoming a senior developer 9 experiences you ll encounter.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20180711 Open hardware meets open science in a multi-microphone hearing aid project.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20180716 Confessions of a recovering Perl hacker.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20180720 A brief history of text-based games and open source.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20180722 Dawn of the Microcomputer- The Altair 8800.md", - "time": "2018-10-24", - "user": "darksun" - }, - { - "file": "sources/talk/20180818 What Did Ada Lovelace-s Program Actually Do.md", - "time": "2018-10-24", - "user": "darksun" - }, - { - "file": "sources/talk/20180820 Keeping patient data safe with open source tools.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20180831 3 innovative open source projects for the new school year.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20180916 The Rise and Demise of RSS.md", - "time": "2018-10-24", - "user": "darksun" - }, - { - "file": "sources/talk/20180930 A Short History of Chaosnet.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20181018 The case for open source classifiers in AI algorithms.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20181019 To BeOS or not to BeOS, that is the Haiku.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20181023 What MMORPGs can teach us about leveling up a heroic developer team.md", - "time": "2018-10-24", - "user": "darksun" - }, - { - "file": "sources/talk/20181024 5 tips for facilitators of agile meetings.md", - "time": "2018-10-25", - "user": "darksun" - }, - { - "file": "sources/talk/20181024 Why it matters that Microsoft released old versions of MS-DOS as open source.md", - "time": "2018-10-25", - "user": "darksun" - }, - { - "file": "sources/talk/20181031 3 scary sysadmin stories.md", - "time": "2018-11-01", - "user": "darksun" - }, - { - "file": "sources/talk/20181031 How open source hardware increases security.md", - "time": "2018-11-01", - "user": "darksun" - }, - { - "file": "sources/talk/20181107 5 signs you are doing continuous testing wrong - Opensource.com.md", - "time": "2018-11-13", - "user": "darksun" - }, - { - "file": "sources/talk/20181107 How open source in education creates new developers.md", - "time": "2018-11-13", - "user": "darksun" - }, - { - "file": "sources/talk/20181112 A Free Guide for Setting Your Open Source Strategy.md", - "time": "2018-11-13", - "user": "darksun" - }, - { - "file": "sources/talk/20181112 The Source History of Cat.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/talk/20181113 Have you seen these personalities in open source.md", - "time": "2018-11-15", - "user": "darksun" - }, - { - "file": "sources/talk/20181114 Analyzing the DNA of DevOps.md", - "time": "2018-11-16", - "user": "darksun" - }, - { - "file": "sources/talk/20181114 Is your startup built on open source- 9 tips for getting started.md", - "time": "2018-11-16", - "user": "darksun" - }, - { - "file": "sources/tech/20091104 Linux-Unix App For Prevention Of RSI (Repetitive Strain Injury).md", - "time": "2018-01-18", - "user": "darksun" - }, - { - "file": "sources/tech/20171111 A CEOs Guide to Emacs.md", - "time": "2018-09-28", - "user": "Xingyu.Wang" - }, - { - "file": "sources/tech/20140510 Managing Digital Files (e.g., Photographs) in Files and Folders.md", - "time": "2018-03-02", - "user": "darksun" - }, - { - "file": "sources/tech/20180902 Learning BASIC Like It-s 1983.md", - "time": "2018-10-24", - "user": "darksun" - }, - { - "file": "sources/tech/20171012 7 Best eBook Readers for Linux.md", - "time": "2018-10-27", - "user": "lctt-bot" - }, - { - "file": "sources/tech/20160922 Annoying Experiences Every Linux Gamer Never Wanted.md", - "time": "2017-12-09", - "user": "Ezio" - }, - { - "file": "sources/tech/20161106 Myths about -dev-urandom.md", - "time": "2018-02-06", - "user": "darksun" - }, - { - "file": "sources/tech/20180928 Quiet log noise with Python and machine learning.md", - "time": "2018-11-24", - "user": "lctt-bot" - }, - { - "file": "sources/tech/20170710 iWant - The Decentralized Peer To Peer File Sharing Commandline Application.md", - "time": "2018-07-13", - "user": "darksun" - }, - { - "file": "sources/tech/20171130 Excellent Business Software Alternatives For Linux.md", - "time": "2018-10-07", - "user": "lctt9972" - }, - { - "file": "sources/tech/20180130 Trying Other Go Versions.md", - "time": "2018-10-11", - "user": "lctt-bot" - }, - { - "file": "sources/tech/20111221 30 Best Sources For Linux - -BSD - Unix Documentation On the Web.md", - "time": "2018-10-08", - "user": "Xingyu.Wang" - }, - { - "file": "sources/tech/20180829 4 open source monitoring tools.md", - "time": "2018-11-14", - "user": "lctt-bot" - }, - { - "file": "sources/tech/20180612 Systemd Services- Reacting to Change.md", - "time": "2018-11-02", - "user": "darksun" - }, - { - "file": "sources/tech/20180518 How to Manage Fonts in Linux.md", - "time": "2018-09-28", - "user": "Xingyu.Wang" - }, - { - "file": "sources/tech/20180619 Systemd Services- Monitoring Files and Directories.md", - "time": "2018-11-02", - "user": "darksun" - }, - { - "file": "sources/tech/20170928 How to create a free baby monitoring system with Gonimo.md", - "time": "2018-01-06", - "user": "darksun" - }, - { - "file": "sources/tech/20180522 How to Enable Click to Minimize On Ubuntu.md", - "time": "2018-10-07", - "user": "lctt9972" - }, - { - "file": "sources/tech/20171006 7 deadly sins of documentation.md", - "time": "2018-01-06", - "user": "darksun" - }, - { - "file": "sources/tech/20171006 Create a Clean-Code App with Kotlin Coroutines and Android Architecture Components.md", - "time": "2018-06-13", - "user": "Xingyu.Wang" - }, - { - "file": "sources/tech/20171010 In Device We Trust Measure Twice Compute Once with Xen Linux TPM 2.0 and TXT.md", - "time": "2018-06-13", - "user": "Xingyu.Wang" - }, - { - "file": "sources/tech/20171018 How to create an e-book chapter template in LibreOffice Writer.md", - "time": "2018-01-07", - "user": "darksun" - }, - { - "file": "sources/tech/20171005 10 Games You Can Play on Linux with Wine.md", - "time": "2018-10-27", - "user": "付峥" - }, - { - "file": "sources/tech/20180611 12 fiction books for Linux and open source types.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/tech/20171027 Share And Upload Files To Compatible Hosting Sites Automatically.md", - "time": "2018-01-05", - "user": "darksun" - }, - { - "file": "sources/tech/20171030 5 open source alternatives to Mint and Quicken for personal finance.md", - "time": "2018-01-05", - "user": "darksun" - }, - { - "file": "sources/tech/20171216 Sysadmin 101- Troubleshooting.md", - "time": "2018-11-20", - "user": "darksun" - }, - { - "file": "sources/tech/20171113 IT disaster recovery- Sysadmins vs. natural disasters - HPE.md", - "time": "2017-12-31", - "user": "darksun" - }, - { - "file": "sources/tech/20171114 Finding Files with mlocate- Part 2.md", - "time": "2017-12-29", - "user": "darksun" - }, - { - "file": "sources/tech/20171116 Unleash Your Creativity – Linux Programs for Drawing and Image Editing.md", - "time": "2017-12-03", - "user": "qhwdw" - }, - { - "file": "sources/tech/20171117 5 open source fonts ideal for programmers.md", - "time": "2017-12-31", - "user": "darksun" - }, - { - "file": "sources/tech/20171121 Finding Files with mlocate- Part 3.md", - "time": "2018-03-04", - "user": "DarkSun" - }, - { - "file": "sources/tech/20181112 Behind the scenes with Linux containers.md", - "time": "2018-11-13", - "user": "darksun" - }, - { - "file": "sources/tech/20170410 Writing a Time Series Database from Scratch.md", - "time": "2018-10-23", - "user": "lctt-bot" - }, - { - "file": "sources/tech/20170523 Best Websites to Download Linux Games.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/tech/20180327 Protecting Code Integrity with PGP - Part 7- Protecting Online Accounts.md", - "time": "2018-11-20", - "user": "Xingyu.Wang" - }, - { - "file": "sources/tech/20171129 Interactive Workflows for Cpp with Jupyter.md", - "time": "2017-12-03", - "user": "Ezio" - }, - { - "file": "sources/tech/20171129 TLDR pages Simplified Alternative To Linux Man Pages.md", - "time": "2017-12-09", - "user": "Ezio" - }, - { - "file": "sources/tech/20171130 Tap the power of community with organized chaos.md", - "time": "2017-12-27", - "user": "darksun" - }, - { - "file": "sources/tech/20171201 Linux Distros That Serve Scientific and Medical Communities.md", - "time": "2018-04-21", - "user": "Ezio" - }, - { - "file": "sources/tech/20181029 Create animated, scalable vector graphic images with MacSVG.md", - "time": "2018-11-01", - "user": "darksun" - }, - { - "file": "sources/tech/20180531 How to Build an Amazon Echo with Raspberry Pi.md", - "time": "2018-09-28", - "user": "Xingyu.Wang" - }, - { - "file": "sources/tech/20171203 Top 20 GNOME Extensions You Should Be Using Right Now.md", - "time": "2017-12-09", - "user": "Ezio" - }, - { - "file": "sources/tech/20180925 9 Easiest Ways To Find Out Process ID (PID) In Linux.md", - "time": "2018-10-28", - "user": "lctt-bot" - }, - { - "file": "sources/tech/20181029 DF-SHOW - A Terminal File Manager Based On An Old DOS Application.md", - "time": "2018-10-30", - "user": "darksun" - }, - { - "file": "sources/tech/20171206 Getting started with Turtl, an open source alternative to Evernote.md", - "time": "2017-12-08", - "user": "darksun" - }, - { - "file": "sources/tech/20181101 Getting started with OKD on your Linux desktop.md", - "time": "2018-11-02", - "user": "darksun" - }, - { - "file": "sources/tech/20171208 GeckoLinux Brings Flexibility and Choice to openSUSE.md", - "time": "2018-01-07", - "user": "darksun" - }, - { - "file": "sources/tech/20171212 Toplip – A Very Strong File Encryption And Decryption CLI Utility.md", - "time": "2018-06-13", - "user": "Xingyu.Wang" - }, - { - "file": "sources/tech/20171215 Top 5 Linux Music Players.md", - "time": "2017-12-22", - "user": "Alex Chen" - }, - { - "file": "sources/tech/20181025 How to write your favorite R functions in Python.md", - "time": "2018-10-30", - "user": "darksun" - }, - { - "file": "sources/tech/20171222 Why the diversity and inclusion conversation must include people with disabilities.md", - "time": "2017-12-27", - "user": "darksun" - }, - { - "file": "sources/tech/20171223 My personal Email setup - Notmuch, mbsync, postfix and dovecot.md", - "time": "2017-12-27", - "user": "darksun" - }, - { - "file": "sources/tech/20171224 My first Rust macro.md", - "time": "2018-03-04", - "user": "DarkSun" - }, - { - "file": "sources/tech/20171226 Top 10 Microsoft Visio Alternatives for Linux.md", - "time": "2017-12-30", - "user": "darksun" - }, - { - "file": "sources/tech/20180101 27 open solutions to everything in education.md", - "time": "2018-01-05", - "user": "darksun" - }, - { - "file": "sources/tech/20181123 How to Build a Netboot Server, Part 1.md", - "time": "2018-11-24", - "user": "darksun" - }, - { - "file": "sources/tech/20180821 How I recorded user behaviour on my competitor-s websites.md", - "time": "2018-08-28", - "user": "darksun" - }, - { - "file": "sources/tech/20181022 Improve login security with challenge-response authentication.md", - "time": "2018-10-23", - "user": "darksun" - }, - { - "file": "sources/tech/20181030 Podman- A more secure way to run containers.md", - "time": "2018-10-31", - "user": "darksun" - }, - { - "file": "sources/tech/20180108 5 arcade-style games in your Linux repository.md", - "time": "2018-01-09", - "user": "darksun" - }, - { - "file": "sources/tech/20180108 Debbugs Versioning- Merging.md", - "time": "2018-01-11", - "user": "darksun" - }, - { - "file": "sources/tech/20180108 SuperTux- A Linux Take on Super Mario Game.md", - "time": "2018-01-09", - "user": "Ezio" - }, - { - "file": "sources/tech/20180108 You GNOME it- Windows and Apple devs get a compelling reason to turn to Linux.md", - "time": "2018-02-04", - "user": "darksun" - }, - { - "file": "sources/tech/20180109 Profiler adventures resolving symbol addresses is hard.md", - "time": "2018-03-04", - "user": "DarkSun" - }, - { - "file": "sources/tech/20181023 How to Check HP iLO Firmware Version from Linux Command Line.md", - "time": "2018-10-31", - "user": "darksun" - }, - { - "file": "sources/tech/20181031 Working with data streams on the Linux command line.md", - "time": "2018-11-01", - "user": "darksun" - }, - { - "file": "sources/tech/20180112 8 KDE Plasma Tips and Tricks to Improve Your Productivity.md", - "time": "2018-01-18", - "user": "darksun" - }, - { - "file": "sources/tech/20180114 Playing Quake 4 on Linux in 2018.md", - "time": "2018-01-15", - "user": "darksun" - }, - { - "file": "sources/tech/20180116 How To Create A Bootable Zorin OS USB Drive.md", - "time": "2018-01-18", - "user": "darksun" - }, - { - "file": "sources/tech/20180118 Rediscovering make- the power behind rules.md", - "time": "2018-06-13", - "user": "Xingyu.Wang" - }, - { - "file": "sources/tech/20180119 Two great uses for the cp command Bash shortcuts.md", - "time": "2018-06-13", - "user": "Xingyu.Wang" - }, - { - "file": "sources/tech/20180122 Ick- a continuous integration system.md", - "time": "2018-02-04", - "user": "darksun" - }, - { - "file": "sources/tech/20180126 An introduction to the Web Simple Perl module a minimalist web framework.md", - "time": "2018-02-04", - "user": "Ezio" - }, - { - "file": "sources/tech/20180129 CopperheadOS Security features installing apps and more.md", - "time": "2018-02-04", - "user": "Ezio" - }, - { - "file": "sources/tech/20181105 5 Easy Tips for Linux Web Browser Security.md", - "time": "2018-11-19", - "user": "darksun" - }, - { - "file": "sources/tech/20180129 WebSphere MQ programming in Python with Zato.md", - "time": "2018-01-31", - "user": "darksun" - }, - { - "file": "sources/tech/20180129 What Happens When You Want to Create a Special Fille with All Special Characters in Linux.md", - "time": "2018-02-04", - "user": "Ezio" - }, - { - "file": "sources/tech/20180130 An introduction to the DomTerm terminal emulator for Linux.md", - "time": "2018-02-04", - "user": "darksun" - }, - { - "file": "sources/tech/20180130 Create and manage MacOS LaunchAgents using Go.md", - "time": "2018-02-02", - "user": "Ezio" - }, - { - "file": "sources/tech/20180130 Graphics and music tools for game development.md", - "time": "2018-02-01", - "user": "darksun" - }, - { - "file": "sources/tech/20180130 Mitigating known security risks in open source libraries.md", - "time": "2018-02-02", - "user": "Ezio" - }, - { - "file": "sources/tech/20180130 Refreshing old computers with Linux.md", - "time": "2018-02-04", - "user": "Ezio" - }, - { - "file": "sources/tech/20180130 tmux - A Powerful Terminal Multiplexer For Heavy Command-Line Linux User.md", - "time": "2018-06-13", - "user": "Xingyu.Wang" - }, - { - "file": "sources/tech/20180131 How to test Webhooks when youre developing locally.md", - "time": "2018-02-02", - "user": "Ezio" - }, - { - "file": "sources/tech/20181119 7 command-line tools for writers - Opensource.com.md", - "time": "2018-11-21", - "user": "darksun" - }, - { - "file": "sources/tech/20180131 Migrating the debichem group subversion repository to Git.md", - "time": "2018-05-25", - "user": "Ezio" - }, - { - "file": "sources/tech/20181112 A Free, Secure And Cross-platform Password Manager.md", - "time": "2018-11-13", - "user": "darksun" - }, - { - "file": "sources/tech/20180823 Getting started with Sensu monitoring.md", - "time": "2018-08-28", - "user": "darksun" - }, - { - "file": "sources/tech/20180201 I Built This - Now What How to deploy a React App on a DigitalOcean Droplet.md", - "time": "2018-02-02", - "user": "Ezio" - }, - { - "file": "sources/tech/20180205 Writing eBPF tracing tools in Rust.md", - "time": "2018-10-11", - "user": "lctt-bot" - }, - { - "file": "sources/tech/20180202 CompositeAcceleration.md", - "time": "2018-02-05", - "user": "darksun" - }, - { - "file": "sources/tech/20180202 Tips for success when getting started with Ansible.md", - "time": "2018-02-05", - "user": "darksun" - }, - { - "file": "sources/tech/20180205 Getting Started with the openbox windows manager in Fedora.md", - "time": "2018-06-13", - "user": "Xingyu.Wang" - }, - { - "file": "sources/tech/20180205 Rancher - Container Management Application.md", - "time": "2018-02-06", - "user": "darksun" - }, - { - "file": "sources/tech/20180206 Power(Shell) to the people.md", - "time": "2018-02-08", - "user": "darksun" - }, - { - "file": "sources/tech/20180207 23 open source audio-visual production tools.md", - "time": "2018-02-09", - "user": "darksun" - }, - { - "file": "sources/tech/20180208 How to start writing macros in LibreOffice Basic.md", - "time": "2018-02-09", - "user": "darksun" - }, - { - "file": "sources/tech/20181114 How to use systemd-nspawn for Linux system recovery.md", - "time": "2018-11-16", - "user": "darksun" - }, - { - "file": "sources/tech/20180209 How to use Twine and SugarCube to create interactive adventure games.md", - "time": "2018-02-11", - "user": "darksun" - }, - { - "file": "sources/tech/20180211 Latching Mutations with GitOps.md", - "time": "2018-04-06", - "user": "Ezio" - }, - { - "file": "sources/tech/20181017 Automating upstream releases with release-bot.md", - "time": "2018-10-18", - "user": "darksun" - }, - { - "file": "sources/tech/20181107 Top 30 OpenStack Interview Questions and Answers.md", - "time": "2018-11-13", - "user": "darksun" - }, - { - "file": "sources/tech/20181109 Must-Have Tools for Writers on the Linux Platform.md", - "time": "2018-11-13", - "user": "darksun" - }, - { - "file": "sources/tech/20181113 An introduction to Udev- The Linux subsystem for managing device events.md", - "time": "2018-11-14", - "user": "darksun" - }, - { - "file": "sources/tech/20180225 What I learnt from building 3 high traffic web applications on an embedded key value store.md", - "time": "2018-04-06", - "user": "Ezio" - }, - { - "file": "sources/tech/20180226 -Getting to Done- on the Linux command line.md", - "time": "2018-03-01", - "user": "darksun" - }, - { - "file": "sources/tech/20180824 Add free books to your eReader- Formatting tips.md", - "time": "2018-08-28", - "user": "darksun" - }, - { - "file": "sources/tech/20180302 How to manage your workstation configuration with Ansible.md", - "time": "2018-03-05", - "user": "darksun" - }, - { - "file": "sources/tech/20180129 The 5 Best Linux Distributions for Development.md", - "time": "2018-10-25", - "user": "Xingyu.Wang" - }, - { - "file": "sources/tech/20180306 Exploring free and open web fonts.md", - "time": "2018-03-08", - "user": "darksun" - }, - { - "file": "sources/tech/20180307 3 open source tools for scientific publishing.md", - "time": "2018-03-12", - "user": "darksun" - }, - { - "file": "sources/tech/20180307 Protecting Code Integrity with PGP - Part 4- Moving Your Master Key to Offline Storage.md", - "time": "2018-03-13", - "user": "darksun" - }, - { - "file": "sources/tech/20180307 What Is sosreport- How To Create sosreport.md", - "time": "2018-03-08", - "user": "darksun" - }, - { - "file": "sources/tech/20180309 A Comparison of Three Linux -App Stores.md", - "time": "2018-03-12", - "user": "darksun" - }, - { - "file": "sources/tech/20180312 ddgr - A Command Line Tool To Search DuckDuckGo From The Terminal.md", - "time": "2018-03-29", - "user": "darksun" - }, - { - "file": "sources/tech/20180314 5 open source card and board games for Linux.md", - "time": "2018-03-20", - "user": "darksun" - }, - { - "file": "sources/tech/20180314 Protecting Code Integrity with PGP - Part 5- Moving Subkeys to a Hardware Device.md", - "time": "2018-03-21", - "user": "darksun" - }, - { - "file": "sources/tech/20180321 Protecting Code Integrity with PGP - Part 6- Using PGP with Git.md", - "time": "2018-03-22", - "user": "darksun" - }, - { - "file": "sources/tech/20180911 Know Your Storage- Block, File - Object.md", - "time": "2018-10-15", - "user": "lctt-bot" - }, - { - "file": "sources/tech/20180324 Memories of writing a parser for man pages.md", - "time": "2018-04-08", - "user": "darksun" - }, - { - "file": "sources/tech/20180326 How to create an open source stack using EFK.md", - "time": "2018-03-29", - "user": "darksun" - }, - { - "file": "sources/tech/20180326 Manage your workstation with Ansible- Automating configuration.md", - "time": "2018-03-29", - "user": "darksun" - }, - { - "file": "sources/tech/20181115 11 Things To Do After Installing elementary OS 5 Juno.md", - "time": "2018-11-16", - "user": "darksun" - }, - { - "file": "sources/tech/20180327 Anna A KVS for any scale.md", - "time": "2018-04-06", - "user": "Ezio" - }, - { - "file": "sources/tech/20180330 Go on very small hardware Part 1.md", - "time": "2018-04-21", - "user": "Ezio" - }, - { - "file": "sources/tech/20180403 Open Source Accounting Program GnuCash 3.0 Released With a New CSV Importer Tool Rewritten in C plus plus.md", - "time": "2018-04-06", - "user": "Ezio" - }, - { - "file": "sources/tech/20180404 Bring some JavaScript to your Java enterprise with Vert.x.md", - "time": "2018-05-31", - "user": "darksun" - }, - { - "file": "sources/tech/20180406 MX Linux- A Mid-Weight Distro Focused on Simplicity.md", - "time": "2018-04-09", - "user": "darksun" - }, - { - "file": "sources/tech/20180407 12 Best GTK Themes for Ubuntu and other Linux Distributions.md", - "time": "2018-04-12", - "user": "darksun" - }, - { - "file": "sources/tech/20180411 5 Best Feed Reader Apps for Linux.md", - "time": "2018-04-17", - "user": "darksun" - }, - { - "file": "sources/tech/20180411 How To Setup Static File Server Instantly.md", - "time": "2018-04-16", - "user": "darksun" - }, - { - "file": "sources/tech/20180411 Replicate your custom Linux settings with DistroTweaks.md", - "time": "2018-04-13", - "user": "darksun" - }, - { - "file": "sources/tech/20180412 Getting started with Jenkins Pipelines.md", - "time": "2018-06-13", - "user": "Xingyu.Wang" - }, - { - "file": "sources/tech/20180413 Redcore Linux Makes Gentoo Easy.md", - "time": "2018-04-16", - "user": "darksun" - }, - { - "file": "sources/tech/20180414 Go on very small hardware Part 2.md", - "time": "2018-04-21", - "user": "Ezio" - }, - { - "file": "sources/tech/20180416 Cgo and Python.md", - "time": "2018-04-21", - "user": "Ezio" - }, - { - "file": "sources/tech/20180416 How To Resize Active-Primary root Partition Using GParted Utility.md", - "time": "2018-04-17", - "user": "darksun" - }, - { - "file": "sources/tech/20180419 Migrating to Linux- Network and System Settings.md", - "time": "2018-04-23", - "user": "darksun" - }, - { - "file": "sources/tech/20180419 Writing Advanced Web Applications with Go.md", - "time": "2018-04-21", - "user": "Ezio" - }, - { - "file": "sources/tech/20180420 A handy way to add free books to your eReader.md", - "time": "2018-04-23", - "user": "darksun" - }, - { - "file": "sources/tech/20180420 How To Remove Password From A PDF File in Linux.md", - "time": "2018-04-24", - "user": "darksun" - }, - { - "file": "sources/tech/20180422 Command Line Tricks For Data Scientists - kade killary.md", - "time": "2018-06-04", - "user": "darksun" - }, - { - "file": "sources/tech/20180423 Breach detection with Linux filesystem forensics - Opensource.com.md", - "time": "2018-04-24", - "user": "darksun" - }, - { - "file": "sources/tech/20180423 Managing virtual environments with Vagrant.md", - "time": "2018-04-24", - "user": "darksun" - }, - { - "file": "sources/tech/20180730 50 Best Ubuntu Apps You Should Be Using Right Now.md", - "time": "2018-08-14", - "user": "darksun" - }, - { - "file": "sources/tech/20180425 An introduction to the GNU Core Utilities - Opensource.com.md", - "time": "2018-04-26", - "user": "geekpi" - }, - { - "file": "sources/tech/20180723 System Snapshot And Restore Utility For Linux.md", - "time": "2018-08-19", - "user": "darksun" - }, - { - "file": "sources/tech/20180428 A Beginners Guide To Flatpak.md", - "time": "2018-05-02", - "user": "darksun" - }, - { - "file": "sources/tech/20180429 The Easiest PDO Tutorial (Basics).md", - "time": "2018-06-19", - "user": "darksun" - }, - { - "file": "sources/tech/20180430 PCGen- An easy way to generate RPG characters.md", - "time": "2018-05-02", - "user": "darksun" - }, - { - "file": "sources/tech/20180503 11 Methods To Find System-Server Uptime In Linux.md", - "time": "2018-05-14", - "user": "darksun" - }, - { - "file": "sources/tech/20180503 How the four components of a distributed tracing system work together.md", - "time": "2018-05-14", - "user": "darksun" - }, - { - "file": "sources/tech/20180509 4MLinux Revives Your Older Computer [Review].md", - "time": "2018-05-10", - "user": "darksun" - }, - { - "file": "sources/tech/20180511 MidnightBSD Could Be Your Gateway to FreeBSD.md", - "time": "2018-05-14", - "user": "darksun" - }, - { - "file": "sources/tech/20180514 MapTool- A robust, flexible virtual tabletop for RPGs.md", - "time": "2018-05-24", - "user": "darksun" - }, - { - "file": "sources/tech/20180515 Termux turns Android into a Linux development environment.md", - "time": "2018-05-18", - "user": "darksun" - }, - { - "file": "sources/tech/20180518 What-s a hero without a villain- How to add one to your Python game.md", - "time": "2018-05-21", - "user": "darksun" - }, - { - "file": "sources/tech/20180522 Advanced use of the less text file viewer in Linux.md", - "time": "2018-05-24", - "user": "darksun" - }, - { - "file": "sources/tech/20180920 Distributed tracing in a microservices world.md", - "time": "2018-09-27", - "user": "darksun" - }, - { - "file": "sources/tech/20180329 Python ChatOps libraries- Opsdroid and Errbot.md", - "time": "2018-10-07", - "user": "Xingyu.Wang" - }, - { - "file": "sources/tech/20180524 TrueOS- A Simple BSD Distribution for the Desktop Users.md", - "time": "2018-06-01", - "user": "darksun" - }, - { - "file": "sources/tech/20180525 How to Set Different Wallpaper for Each Monitor in Linux.md", - "time": "2018-05-31", - "user": "darksun" - }, - { - "file": "sources/tech/20180529 How the Go runtime implements maps efficiently.md", - "time": "2018-07-04", - "user": "Ezio" - }, - { - "file": "sources/tech/20180529 Manage your workstation with Ansible- Configure desktop settings.md", - "time": "2018-05-31", - "user": "darksun" - }, - { - "file": "sources/tech/20180530 Introduction to the Pony programming language.md", - "time": "2018-05-31", - "user": "darksun" - }, - { - "file": "sources/tech/20180914 A day in the life of a log message.md", - "time": "2018-09-16", - "user": "darksun" - }, - { - "file": "sources/tech/20180531 Qalculate- - The Best Calculator Application in The Entire Universe.md", - "time": "2018-06-04", - "user": "darksun" - }, - { - "file": "sources/tech/20180601 3 open source music players for Linux.md", - "time": "2018-06-04", - "user": "darksun" - }, - { - "file": "sources/tech/20180601 Get Started with Snap Packages in Linux.md", - "time": "2018-06-04", - "user": "darksun" - }, - { - "file": "sources/tech/20180604 4 Firefox extensions worth checking out.md", - "time": "2018-06-06", - "user": "darksun" - }, - { - "file": "sources/tech/20180604 BootISO - A Simple Bash Script To Securely Create A Bootable USB Device From ISO File.md", - "time": "2018-08-03", - "user": "darksun" - }, - { - "file": "sources/tech/20180605 How to use autofs to mount NFS shares.md", - "time": "2018-06-06", - "user": "darksun" - }, - { - "file": "sources/tech/20180605 Sound themes in Linux- What every user should know.md", - "time": "2018-06-06", - "user": "darksun" - }, - { - "file": "sources/tech/20180606 Working with modules in Fedora 28.md", - "time": "2018-06-08", - "user": "darksun" - }, - { - "file": "sources/tech/20180608 How to Install and Use Flatpak on Linux.md", - "time": "2018-06-11", - "user": "darksun" - }, - { - "file": "sources/tech/20180608 How to use screen scraping tools to extract data from the web.md", - "time": "2018-06-19", - "user": "darksun" - }, - { - "file": "sources/tech/20180609 4 tips for getting an older relative online with Linux.md", - "time": "2018-06-11", - "user": "darksun" - }, - { - "file": "sources/tech/20180817 AryaLinux- A Distribution and a Platform.md", - "time": "2018-08-19", - "user": "darksun" - }, - { - "file": "sources/tech/20180611 3 open source alternatives to Adobe Lightroom.md", - "time": "2018-06-15", - "user": "darksun" - }, - { - "file": "sources/tech/20180612 7 open source tools to make literature reviews easy.md", - "time": "2018-06-15", - "user": "darksun" - }, - { - "file": "sources/tech/20180612 Using Ledger for YNAB-like envelope budgeting.md", - "time": "2018-07-05", - "user": "darksun" - }, - { - "file": "sources/tech/20180614 Bash tips for everyday at the command line.md", - "time": "2018-06-19", - "user": "darksun" - }, - { - "file": "sources/tech/20180914 Freespire Linux- A Great Desktop for the Open Source Purist.md", - "time": "2018-09-18", - "user": "darksun" - }, - { - "file": "sources/tech/20180918 Cozy Is A Nice Linux Audiobook Player For DRM-Free Audio Files.md", - "time": "2018-09-19", - "user": "darksun" - }, - { - "file": "sources/tech/20180618 Write fast apps with Pronghorn, a Java framework.md", - "time": "2018-06-20", - "user": "darksun" - }, - { - "file": "sources/tech/20180621 How to connect to a remote desktop from Linux.md", - "time": "2018-06-28", - "user": "darksun" - }, - { - "file": "sources/tech/20180621 Troubleshooting a Buildah script.md", - "time": "2018-06-28", - "user": "darksun" - }, - { - "file": "sources/tech/20180622 Use LVM to Upgrade Fedora.md", - "time": "2018-06-28", - "user": "darksun" - }, - { - "file": "sources/tech/20180806 Recreate Famous Data Decryption Effect Seen On Sneakers Movie.md", - "time": "2018-08-23", - "user": "darksun" - }, - { - "file": "sources/tech/20180625 The life cycle of a software bug.md", - "time": "2018-06-28", - "user": "darksun" - }, - { - "file": "sources/tech/20180626 How To Search If A Package Is Available On Your Linux Distribution Or Not.md", - "time": "2018-06-28", - "user": "darksun" - }, - { - "file": "sources/tech/20180629 100 Best Ubuntu Apps.md", - "time": "2018-07-02", - "user": "darksun" - }, - { - "file": "sources/tech/20180629 Discover hidden gems in LibreOffice.md", - "time": "2018-07-02", - "user": "darksun" - }, - { - "file": "sources/tech/20180629 How To Get Flatpak Apps And Games Built With OpenGL To Work With Proprietary Nvidia Graphics Drivers.md", - "time": "2018-07-04", - "user": "darksun" - }, - { - "file": "sources/tech/20180629 Is implementing and managing Linux applications becoming a snap.md", - "time": "2018-07-04", - "user": "darksun" - }, - { - "file": "sources/tech/20180629 SoCLI - Easy Way To Search And Browse Stack Overflow From The Terminal.md", - "time": "2018-07-02", - "user": "darksun" - }, - { - "file": "sources/tech/20180701 12 Things to do After Installing Linux Mint 19.md", - "time": "2018-07-04", - "user": "darksun" - }, - { - "file": "sources/tech/20180702 5 open source alternatives to Skype.md", - "time": "2018-07-04", - "user": "darksun" - }, - { - "file": "sources/tech/20180702 Diggs v4 launch an optimism born of necessity.md", - "time": "2018-07-05", - "user": "geekpi" - }, - { - "file": "sources/tech/20180816 Designing your garden with Edraw Max - FOSS adventures.md", - "time": "2018-08-18", - "user": "darksun" - }, - { - "file": "sources/tech/20180703 10 killer tools for the admin in a hurry.md", - "time": "2018-07-05", - "user": "darksun" - }, - { - "file": "sources/tech/20180703 AGL Outlines Virtualization Scheme for the Software Defined Vehicle.md", - "time": "2018-07-04", - "user": "Ezio" - }, - { - "file": "sources/tech/20180704 BASHing data- Truncated data items.md", - "time": "2018-07-05", - "user": "darksun" - }, - { - "file": "sources/tech/20180706 Using Ansible to set up a workstation.md", - "time": "2018-07-09", - "user": "darksun" - }, - { - "file": "sources/tech/20180708 simple and elegant free podcast player.md", - "time": "2018-07-09", - "user": "darksun" - }, - { - "file": "sources/tech/20180709 5 Firefox extensions to protect your privacy.md", - "time": "2018-07-13", - "user": "darksun" - }, - { - "file": "sources/tech/20180924 5 ways to play old-school games on a Raspberry Pi.md", - "time": "2018-09-25", - "user": "darksun" - }, - { - "file": "sources/tech/20180710 The aftermath of the Gentoo GitHub hack.md", - "time": "2018-07-13", - "user": "darksun" - }, - { - "file": "sources/tech/20180710 Users, Groups, and Other Linux Beasts.md", - "time": "2018-07-16", - "user": "darksun" - }, - { - "file": "sources/tech/20180711 5 open source racing and flying games for Linux.md", - "time": "2018-07-16", - "user": "darksun" - }, - { - "file": "sources/tech/20180923 Gunpoint is a Delight for Stealth Game Fans.md", - "time": "2018-09-25", - "user": "darksun" - }, - { - "file": "sources/tech/20180719 Building tiny container images.md", - "time": "2018-08-02", - "user": "darksun" - }, - { - "file": "sources/tech/20180919 Streama - Setup Your Own Streaming Media Server In Minutes.md", - "time": "2018-09-20", - "user": "darksun" - }, - { - "file": "sources/tech/20180920 Record Screen in Ubuntu Linux With Kazam -Beginner-s Guide.md", - "time": "2018-09-21", - "user": "darksun" - }, - { - "file": "sources/tech/20181015 An introduction to Ansible Operators in Kubernetes.md", - "time": "2018-10-18", - "user": "darksun" - }, - { - "file": "sources/tech/20180724 How To Mount Google Drive Locally As Virtual File System In Linux.md", - "time": "2018-07-26", - "user": "darksun" - }, - { - "file": "sources/tech/20180725 Best Online Linux Terminals and Online Bash Editors.md", - "time": "2018-07-30", - "user": "darksun" - }, - { - "file": "sources/tech/20180828 Linux for Beginners- Moving Things Around.md", - "time": "2018-09-03", - "user": "darksun" - }, - { - "file": "sources/tech/20180816 Garbage collection in Perl 6.md", - "time": "2018-08-17", - "user": "darksun" - }, - { - "file": "sources/tech/20180727 4 Ways to Customize Xfce and Give it a Modern Look.md", - "time": "2018-07-30", - "user": "darksun" - }, - { - "file": "sources/tech/20180727 Download Subtitles Via Right Click From File Manager Or Command Line With OpenSubtitlesDownload.py.md", - "time": "2018-08-02", - "user": "darksun" - }, - { - "file": "sources/tech/20180829 Containers in Perl 6.md", - "time": "2018-08-31", - "user": "darksun" - }, - { - "file": "sources/tech/20180731 What-s in a container image- Meeting the legal challenges.md", - "time": "2018-08-03", - "user": "darksun" - }, - { - "file": "sources/tech/20180801 Getting started with Standard Notes for encrypted note-taking.md", - "time": "2018-08-03", - "user": "darksun" - }, - { - "file": "sources/tech/20180801 Hiri is a Linux Email Client Exclusively Created for Microsoft Exchange.md", - "time": "2018-08-03", - "user": "darksun" - }, - { - "file": "sources/tech/20180801 Migrating Perl 5 code to Perl 6.md", - "time": "2018-08-03", - "user": "darksun" - }, - { - "file": "sources/tech/20180810 Strawberry- Quality sound, open source music player.md", - "time": "2018-08-14", - "user": "darksun" - }, - { - "file": "sources/tech/20180802 Walkthrough On How To Use GNOME Boxes.md", - "time": "2018-08-03", - "user": "darksun" - }, - { - "file": "sources/tech/20180803 How to use Fedora Server to create a router - gateway.md", - "time": "2018-08-06", - "user": "DarkSun" - }, - { - "file": "sources/tech/20180830 A quick guide to DNF for yum users.md", - "time": "2018-09-03", - "user": "darksun" - }, - { - "file": "sources/tech/20180806 How ProPublica Illinois uses GNU Make to load 1.4GB of data every day.md", - "time": "2018-08-08", - "user": "darksun" - }, - { - "file": "sources/tech/20181003 Oomox - Customize And Create Your Own GTK2, GTK3 Themes.md", - "time": "2018-10-09", - "user": "darksun" - }, - { - "file": "sources/tech/20180822 9 flowchart and diagramming tools for Linux.md", - "time": "2018-08-23", - "user": "DarkSun" - }, - { - "file": "sources/tech/20180806 Use Gstreamer and Python to rip CDs.md", - "time": "2018-08-08", - "user": "darksun" - }, - { - "file": "sources/tech/20180929 Use Cozy to Play Audiobooks in Linux.md", - "time": "2018-09-30", - "user": "darksun" - }, - { - "file": "sources/tech/20180514 Tuptime - A Tool To Report The Historical Uptime Of Linux System.md", - "time": "2018-08-10", - "user": "darksun" - }, - { - "file": "sources/tech/20180809 Getting started with Postfix, an open source mail transfer agent.md", - "time": "2018-08-10", - "user": "darksun" - }, - { - "file": "sources/tech/20180830 How to scale your website across all mobile devices.md", - "time": "2018-09-04", - "user": "darksun" - }, - { - "file": "sources/tech/20180809 Perform robust unit tests with PyHamcrest.md", - "time": "2018-08-10", - "user": "darksun" - }, - { - "file": "sources/tech/20180802 Top 5 CAD Software Available for Linux in 2018.md", - "time": "2018-08-19", - "user": "darksun" - }, - { - "file": "sources/tech/20180810 Use Plank On Multiple Monitors Without Creating Multiple Docks With autoplank.md", - "time": "2018-08-14", - "user": "darksun" - }, - { - "file": "sources/tech/20180925 Taking the Audiophile Linux distro for a spin.md", - "time": "2018-09-26", - "user": "darksun" - }, - { - "file": "sources/tech/20180828 An Introduction to Quantum Computing with Open Source Cirq Framework.md", - "time": "2018-08-29", - "user": "darksun" - }, - { - "file": "sources/tech/20180814 5 open source strategy and simulation games for Linux.md", - "time": "2018-08-15", - "user": "darksun" - }, - { - "file": "sources/tech/20181018 4 open source alternatives to Microsoft Access.md", - "time": "2018-10-19", - "user": "darksun" - }, - { - "file": "sources/tech/20180716 Users, Groups and Other Linux Beasts- Part 2.md", - "time": "2018-07-24", - "user": "darksun" - }, - { - "file": "sources/tech/20180814 HTTP request routing and validation with gorilla-mux.md", - "time": "2018-08-16", - "user": "darksun" - }, - { - "file": "sources/tech/20180815 Happy birthday, GNOME- 6 reasons to love this Linux desktop.md", - "time": "2018-08-16", - "user": "darksun" - }, - { - "file": "sources/tech/20180817 Cloudgizer- An introduction to a new open source web development tool.md", - "time": "2018-08-18", - "user": "darksun" - }, - { - "file": "sources/tech/20140929 A Word from The Beegoist - Richard Kenneth Eng - Medium.md", - "time": "2018-08-19", - "user": "darksun" - }, - { - "file": "sources/tech/20180828 Orion Is A QML - C-- Twitch Desktop Client With VODs And Chat Support.md", - "time": "2018-08-31", - "user": "darksun" - }, - { - "file": "sources/tech/20180906 What a shell dotfile can do for you.md", - "time": "2018-09-07", - "user": "darksun" - }, - { - "file": "sources/tech/20180912 How subroutine signatures work in Perl 6.md", - "time": "2018-09-13", - "user": "darksun" - }, - { - "file": "sources/tech/20180912 How to turn on an LED with Fedora IoT.md", - "time": "2018-09-13", - "user": "darksun" - }, - { - "file": "sources/tech/20181005 Dbxfs - Mount Dropbox Folder Locally As Virtual File System In Linux.md", - "time": "2018-10-08", - "user": "darksun" - }, - { - "file": "sources/tech/20181005 How to use Kolibri to access educational material offline.md", - "time": "2018-10-08", - "user": "darksun" - }, - { - "file": "sources/tech/20181011 The First Beta of Haiku is Released After 16 Years of Development.md", - "time": "2018-10-12", - "user": "darksun" - }, - { - "file": "sources/tech/20181016 piwheels- Speedy Python package installation for the Raspberry Pi.md", - "time": "2018-10-18", - "user": "darksun" - }, - { - "file": "sources/tech/20181018 TimelineJS- An interactive, JavaScript timeline building tool.md", - "time": "2018-10-19", - "user": "darksun" - } - ] -} From 0e723d0e0ef3d9bf21568e1e0f42e11335def859 Mon Sep 17 00:00:00 2001 From: oneforalone Date: Sat, 1 Dec 2018 11:02:27 +0800 Subject: [PATCH 07/12] translating --- sources/tech/20171111 A CEOs Guide to Emacs.md | 1 + 1 file changed, 1 insertion(+) diff --git a/sources/tech/20171111 A CEOs Guide to Emacs.md b/sources/tech/20171111 A CEOs Guide to Emacs.md index a694d07917..54b0d30238 100644 --- a/sources/tech/20171111 A CEOs Guide to Emacs.md +++ b/sources/tech/20171111 A CEOs Guide to Emacs.md @@ -1,3 +1,4 @@ +[#]:translator:(oneforalone) A CEO's Guide to Emacs ============================================================ From cd4120cf3c3b3f1334370e3234e4c857ee37ff46 Mon Sep 17 00:00:00 2001 From: Jamkr Date: Sat, 1 Dec 2018 13:28:20 +0800 Subject: [PATCH 08/12] Translated 20171108 Continuous infrastructure- The other CI --- ...Continuous infrastructure- The other CI.md | 120 ------------------ ...Continuous infrastructure- The other CI.md | 111 ++++++++++++++++ 2 files changed, 111 insertions(+), 120 deletions(-) delete mode 100644 sources/tech/20171108 Continuous infrastructure- The other CI.md create mode 100644 translated/tech/20171108 Continuous infrastructure- The other CI.md diff --git a/sources/tech/20171108 Continuous infrastructure- The other CI.md b/sources/tech/20171108 Continuous infrastructure- The other CI.md deleted file mode 100644 index 757ec2a723..0000000000 --- a/sources/tech/20171108 Continuous infrastructure- The other CI.md +++ /dev/null @@ -1,120 +0,0 @@ -Translating by Jamskr - -Continuous infrastructure: The other CI -====== -![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/BIZ_darwincloud_520x292_0311LL.png?itok=74DLgd8Q) - -Continuous delivery (CD) and continuous integration (CI) are two well-known aspects of DevOps. But the CI in vogue today is missing a critical "I:" infrastructure. - -There was a time when "infrastructure" meant headless black boxes, enormous server rooms, and towering racks--not to mention procurement processes that stretched for months and load estimates that erred on the side of surplus. Then came the virtual machine revolution, which made the infrastructure, well, virtual--and the world has never been the same. We no longer need to manage brick-and-mortar boxes. We can create and destroy, start and stop, upgrade and downgrade machines with just a few clicks. - -There's a popular story about a bank that went digital and introduced online forms, which customers needed to fill out manually, print, and snail-mail to the bank. That's where we are today with infrastructure: using new technology to do things the same old way. - -In this article, we'll look at progressive infrastructure management, treating infrastructure as a versioned artifact and exploring the concept of immutable servers. In a subsequent post, we'll look at how open source tools can be used to achieve continuous infrastructure. - - -![continuous infrastructure pipeline][2] - - -The in-practice continuous infrastructure pipeline - -This is the familiar CI, release-early, release-often cycle pipeline. This pipeline is missing a key component: infrastructure. - -Pop quiz: - - * How do you create and upgrade your infrastructure? - * How do you control and track changes to your infrastructure? - * How does your infrastructure scale with your business? - * How do you ensure tests on the right infrastructure configuration? - - - -To answer these questions, introduce continuous infrastructure. Split the CI build pipeline into continuous integration code (CIc) and continuous integration infrastructure (CIi) to develop and build code and infrastructure in parallel, converging the two for unified test and release. Make infrastructure a first-class citizen of the CI pipeline. - - -![pipeline with infrastructure][4] - - -CI pipeline with continuous infrastructure - -The defining aspects of CIi include: - -**1\. Code** - -Create infrastructure by code, not by installation. Infrastructure as code (IaC) is the contemporary method used to develop infrastructure from configuration scripts. These scripts follow the typical development life cycle of coding and unit tests (see the Terraform script below for an example). - -**2\. Version** - -The IaC artifacts are versioned in the source repository. This brings all the advantages of version control to the infrastructure: consistency, traceability, branching, and tagging. - -**3\. Manage** - -With coded and versioned infrastructure, you can apply the familiar test and release processes to manage infrastructure development. - -CIi offers the following advantages: - -**1\. Consistency** - -Versioned and tagged infrastructure means you unambiguously know the components and configuration of the system you are using. This establishes an excellent DevOps practice to identify and manage infrastructure consistently. - -**2\. Reproducibility** - -With infrastructure tagged and baselined, recreating infrastructure is easy. Think of how often you've heard this: "But it works on my machine!" Now you can reproduce a production-like environment quickly in a local test bench to remove environment as a variable of your debug cycle. - -**3\. Traceability** - -How many times have you gone through history to find out who changed the permissions of a folder, or who upgraded the **ssh** package? Coded, versioned, released infrastructure eliminates ad hoc changes, bringing easy traceability and predictability to infrastructure management. - -**4\. Automation** - -With scriptable infrastructure, automation is the next logical step. Automation lets you create infrastructure on demand and destroy it when you're done, so you can focus your valuable time and energy on more productive tasks. - -**5\. Immutability** - -CIi brings innovations such as immutable infrastructure. Instead of upgrading, you can simply create new infrastructure components (see the note on immutable infrastructure below). - -Continuous infrastructure is about evolving run-environments with run-artifacts. Treat infrastructure like code, and take it through proven DevOps processes. The traditional CI is redefined to include that missing "i," leading to a coherent CD. - -**(CIc + CIi) = CI -> CD** - -## Infrastructure as code (IaC) - -A key enabler for CIi pipeline is infrastructure as code (IaC). IaC is the mechanism for creating and upgrading infrastructure with configuration files. These configuration files are developed like code and versioned in version control system. The files follow the usual code development life cycle: unit test, commit, build, and release. IaC process brings all advantages of version control for infrastructure development, such as tagging, versioning consistency, and change traceability. - -Here's a sample Terraform script to create a two-tier infrastructure on AWS, consisting of a virtual private cloud (VPC), an elastic load balancer (ELB), security groups, and an NGINX server. [Terraform][5] is an open source tool to create and change infrastructure through scripts. - - -![terraform script][7] - - -Sample Terraform script to create two-tier infrastructure on AWS - -The complete script is available on [GitHub][8]. - -## Immutable infrastructure - -You have several VMs running and need to apply a security patch. A common approach is to update all systems individually using a remote push script. - -Instead of updating the old systems, how about throwing them away and deploying new systems with a security patch installed? This is immutable infrastructure. Since the previous version of infrastructure is versioned and tagged, installing the patch is simply a matter of updating the script and pushing it through the release pipeline. - -Now do you see why infrastructure should be a first-class citizen of the CI pipeline? - --------------------------------------------------------------------------------- - -via: https://opensource.com/article/17/11/continuous-infrastructure-other-ci - -作者:[About The Author;Girish Managoli;With About Years;Experience In The Software It Industry;Girish Presently Holds Chief Architect Capacity At Mindtree;A Global It Services Organization;Based In India. Specialising In Paas;Saas Platforms;Girish Is Architect Of;I Got][a] -译者:[lujun9972](https://github.com/lujun9972) -校对:[校对者ID](https://github.com/校对者ID) - -本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出 - -[a]:https://opensource.com -[1]:/file/376916 -[2]:https://opensource.com/sites/default/files/images/life-uploads/figure1.jpg (continuous infrastructure pipeline in use) -[3]:/file/376921 -[4]:https://opensource.com/sites/default/files/images/life-uploads/figure2.jpg (CI pipeline with infrastructure) -[5]:https://github.com/hashicorp/terraform -[6]:/file/376926 -[7]:https://opensource.com/sites/default/files/images/life-uploads/figure3_0.png (sample terraform script) -[8]:https://github.com/terraform-providers/terraform-provider-aws/tree/master/examples/two-tier diff --git a/translated/tech/20171108 Continuous infrastructure- The other CI.md b/translated/tech/20171108 Continuous infrastructure- The other CI.md new file mode 100644 index 0000000000..1e8395e80f --- /dev/null +++ b/translated/tech/20171108 Continuous infrastructure- The other CI.md @@ -0,0 +1,111 @@ +持续基础设施: 另一个 CI +====== + +![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/BIZ_darwincloud_520x292_0311LL.png?itok=74DLgd8Q) + +持续交付(CD)和持续集成(CI)是 DevOps 的两个众所周知的方面。但在 CI 大肆流行的今天却忽略了另一个关键性的 "I":基础设施(infrastructure)。 + +曾经有一段时间 “基础设施”就意味着无头的黑盒子,庞大的服务器,和高耸的机架——更不用说漫长的采购流程和对盈余负载的错误估计。后来到了虚拟机时代,把基础设施处理得很好,虚拟化——以前的世界从未有过这样。我们不再需要管理实体的服务器。仅仅是简单的点击,我们就可以创建和销毁,开始和停止,升级和降级我们的服务器。 + +有一个关于银行的流行的故事,它们实现了数字化,并且引入了在线表格,用户需要手动填写表格,打印,然后邮寄回银行。这就是我们今天要说的基础设施:使用新技术来做和以前一样的事情。 + +在这篇文章中,我们会看到在基础设施管理方面的进步,将基础设施视为一个版本化的组件并试着探索服务器一致性的概念。在后面的文章中,我们将了解如何使用开源工具来实现持续的基础设施。 + +![continuous infrastructure pipeline][2] + +实践中的持续集成管道 + +这是我们熟悉的 CI,尽早发布,经常发布的循环管道。这个管道缺少一个关键的组件:基础设施。 + +突击小测试: + + * 你怎样创建和升级你的基础设施? + * 你怎样控制和追溯基础设施的改变? + * 你的基础设施是如何与你的业务进行匹配的? + * 你是如何确保在正确的基础设施配置上进行测试的? + +要回答这些问题,就要了解持续基础设施。把 CI 构建流程分为代码持续集成(CIc)和基础设施持续集成(CIi)来并行开发代码和基础设施,再将两者融合到一起进行测试 。把基础设施构建视为CI流程中的重要的一环。 + +![pipeline with infrastructure][4] + +包含持续基础设施的 CI 管道流程 + +关于 CIi 定义的几个方面: + +**1\. 代码** + +通过代码来创建基础设施架构,而不是通过安装。使用配置脚代码是现代最流行的创建基础设施(IaC)的方法。这些脚本遵循典型的编码和单元测试周期(请参阅下面关于 Terraform 脚本的示例)。 + +**2\. 版本** + +IaC 组件在源码仓库中进行版本管理。这让基础设施的拥有了版本控制的所有好处:一致性,可追溯性,分支和标记。 + +**3\. 管理** + +通过编码和版本化的基础设施管理,你可以使用你所熟悉的测试和发布流程来管理基础设施的开发。 + +CIi 提供了下面的这些优势: + +**1\. 一致性** + +版本化和标记基础设施意味着你可以清楚的知道你的系统使用了哪些组件和配置。这是建立了一个非常好的 DevOps 实践,用来鉴定和管理基础设施的一致性。 + +**2\. 可重现性** + +通过基础设施的标记和基线,重建基础设施变得非常容易。想想你是否经常听到这个:“但是它在我的机器上可以运行!”现在,你可以在本地的测试平台中快速重现类似生产环境,从而将环境像变量一样在你的调试过程中删除。 + +**3\. 可追溯性性** + +你是否还记得曾经有过多少次寻找到底是谁更改了文件夹权限的经历,或者是谁升级了 `ssh` 包?编码,版本化,发布的基础设施消除了临时的变更,为基础设施的管理带来了可追踪性和可预测性。 + +**4\. 自动化** + +借助脚本化的基础架构,自动化是下一个合乎逻辑的步骤。自动化允许你按需创建基础设施,并在使用完成后删除它,所以你可以将更多宝贵的时间和精力用在更重要的任务上。 + +**5\. 不变性** + +CIi 不可变基础设施等创新。你可以创建一个新的基础设施组件而不是通过升级(请参阅下面有关不可变设施的说明)。 + +持续基础设施是从运行基础环境到运行基础组件的进化。像处理代码一样,通过认证的 DevOps 流程来完成。对传统的 CI 的重新定义包含了缺少的那个 “i”,从而形成了连贯的 CD 。 + +**(CIc + CIi) = CI -> CD** + +## 基础设施代码 (IaC) + +CIi 管道的一个关键推动因素是基础设施代码(IaC)。IaC 是一种使用配置文件进行基础设施创建和升级的机制。这些配置文件像其他的代码一样进行开发,并且使用版本管理系统进行管理。这些文件遵循一般的代码开发流程:单元测试,提交,构建,和发布。IaC 流程拥有版本控制带给基础设施开发的所有好处,像标记,版本一致性,和修改可追溯。 + +这有一个简单的 Terraform 脚本用来用来在 AWS 上创建一个双层基础设施的简单示例,包括虚拟私有云(VPC),弹性负载(ELB),安全组和一个 NGINX 服务器。Terraform 是一个通过通过脚本创建和更改基础设施架构和开源工具。 + +![terraform script][7] + +Terraform 脚本创建双层架构设施的简单示例 + +完整的脚本请参见 [GitHub][8]。 + +## 基础设施架构的不变性 + +你有几个正在运行的 VM 需要更新安全补丁。一个常见的做法是推送一个远程脚本单独更新每个系统。 + +如何更新一个旧系统,如何丢弃它们并布置安装了新安全补丁的新系统?这就是基础设施的不变性。通过之前对基础设施的版本控制和标记,所以安装补丁只需要更新下脚本并将其推送到发布管道即可。 + +现在你知道为什么要说基础设施在 CI 管道中特别重要了吗? + +-------------------------------------------------------------------------------- + +via: https://opensource.com/article/17/11/continuous-infrastructure-other-ci + +作者:[About The Author;Girish Managoli;With About Years;Experience In The Software It Industry;Girish Presently Holds Chief Architect Capacity At Mindtree;A Global It Services Organization;Based In India. Specialising In Paas;Saas Platforms;Girish Is Architect Of;I Got][a] +译者:[lujun9972](https://github.com/lujun9972) +校对:[Jamskr](https://github.com/Jamskr) + +本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出 + +[a]:https://opensource.com +[1]:/file/376916 +[2]:https://opensource.com/sites/default/files/images/life-uploads/figure1.jpg (continuous infrastructure pipeline in use) +[3]:/file/376921 +[4]:https://opensource.com/sites/default/files/images/life-uploads/figure2.jpg (CI pipeline with infrastructure) +[5]:https://github.com/hashicorp/terraform +[6]:/file/376926 +[7]:https://opensource.com/sites/default/files/images/life-uploads/figure3_0.png (sample terraform script) +[8]:https://github.com/terraform-providers/terraform-provider-aws/tree/master/examples/two-tier From f8fd013e0d5433fcbba809f182bfe90a23424b85 Mon Sep 17 00:00:00 2001 From: Jamkr Date: Sat, 1 Dec 2018 13:51:20 +0800 Subject: [PATCH 09/12] [Translating] Exploring the Linux kernel- The secrets of Kconfig-kbuild --- ...Exploring the Linux kernel- The secrets of Kconfig-kbuild.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sources/tech/20181011 Exploring the Linux kernel- The secrets of Kconfig-kbuild.md b/sources/tech/20181011 Exploring the Linux kernel- The secrets of Kconfig-kbuild.md index 8ee4f34897..2fd085eda0 100644 --- a/sources/tech/20181011 Exploring the Linux kernel- The secrets of Kconfig-kbuild.md +++ b/sources/tech/20181011 Exploring the Linux kernel- The secrets of Kconfig-kbuild.md @@ -1,3 +1,5 @@ +Translating by Jamskr + Exploring the Linux kernel: The secrets of Kconfig/kbuild ====== Dive into understanding how the Linux config/build system works. From 97450f5312163efe54c6b4ac9df3af9f76e11c99 Mon Sep 17 00:00:00 2001 From: FelixYFZ <33593534+FelixYFZ@users.noreply.github.com> Date: Sat, 1 Dec 2018 14:21:58 +0800 Subject: [PATCH 10/12] Update 20180326 Manage your workstation with Ansible- Automating configuration.md Translating by FelixYFZ --- ...e your workstation with Ansible- Automating configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sources/tech/20180326 Manage your workstation with Ansible- Automating configuration.md b/sources/tech/20180326 Manage your workstation with Ansible- Automating configuration.md index 21821a070c..b504b48ae0 100644 --- a/sources/tech/20180326 Manage your workstation with Ansible- Automating configuration.md +++ b/sources/tech/20180326 Manage your workstation with Ansible- Automating configuration.md @@ -1,4 +1,4 @@ -Manage your workstation with Ansible: Automating configuration +Manage your workstation with Ansible: Automating configuration Translating By FelixYFZ ====== ![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/robot_arm_artificial_ai.png?itok=8CUU3U_7) From 77bcb253a8a54e07eba12bd4709a3a53dd60196d Mon Sep 17 00:00:00 2001 From: Auk7F7 <34982730+Auk7F7@users.noreply.github.com> Date: Sat, 1 Dec 2018 16:51:29 +0800 Subject: [PATCH 11/12] Delete 20180523 How to dual-boot Linux and Windows.md --- ...0523 How to dual-boot Linux and Windows.md | 224 ------------------ 1 file changed, 224 deletions(-) delete mode 100644 sources/tech/20180523 How to dual-boot Linux and Windows.md diff --git a/sources/tech/20180523 How to dual-boot Linux and Windows.md b/sources/tech/20180523 How to dual-boot Linux and Windows.md deleted file mode 100644 index 372097c866..0000000000 --- a/sources/tech/20180523 How to dual-boot Linux and Windows.md +++ /dev/null @@ -1,224 +0,0 @@ -translating by Auk7F7 -How to dual-boot Linux and Windows -====== - -![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/migration_innovation_computer_software.png?itok=VCFLtd0q) - -Even though Linux is a great operating system with widespread hardware and software support, the reality is that sometimes you have to use Windows, perhaps due to key apps that won't run under Linux. Thankfully, dual-booting Windows and Linux is very straightforward—and I'll show you how to set it up, with Windows 10 and Ubuntu 18.04, in this article. - -Before you get started, make sure you've backed up your computer. Although the dual-boot setup process is not very involved, accidents can still happen. So take the time to back up your important files in case chaos theory comes into play. In addition to backing up your files, consider taking an image backup of the disk as well, though that's not required and can be a more advanced process. - -### Prerequisites - -To get started, you will need the following five items: - -#### 1\. Two USB flash drives (or DVD-Rs) - -I recommend installing Windows and Ubuntu via flash drives since they're faster than DVDs. It probably goes without saying, but creating bootable media erases everything on the flash drive. Therefore, make sure the flash drives are empty or contain data you don't care about losing. - -If your machine doesn't support booting from USB, you can create DVD media instead. Unfortunately, because no two computers seem to have the same DVD-burning software, I can't walk you through that process. However, if your DVD-burning application has an option to burn from an ISO image, that's the option you need. - -#### 2\. A Windows 10 license - -If Windows 10 came with your PC, the license will be built into the computer, so you don't need to worry about entering it during installation. If you bought the retail edition, you should have a product key, which you will need to enter during the installation process. - -#### 3\. Windows 10 Media Creation Tool - -Download and launch the Windows 10 [Media Creation Tool][1]. Once you launch the tool, it will walk you through the steps required to create the Windows media on a USB or DVD-R. Note: Even if you already have Windows 10 installed, it's a good idea to create bootable media anyway, just in case something goes wrong and you need to reinstall it. - -#### 4\. Ubuntu 18.04 installation media - -Download the [Ubuntu 18.04][2] ISO image. - -#### 5\. Etcher software (for making a bootable Ubuntu USB drive) - -For creating bootable media for any Linux distribution, I recommend [Etcher][3]. Etcher works on all three major operating systems (Linux, MacOS, and Windows) and is careful not to let you overwrite your current operating system partition. - -Once you have downloaded and launched Etcher, click Select image, and point it to the Ubuntu ISO you downloaded in step 4. Next, click Select drive to choose your flash drive, and click Flash! to start the process of turning a flash drive into an Ubuntu installer. (If you're using a DVD-R, use your computer's DVD-burning software instead.) - -### Install Windows and Ubuntu - -You should be ready to begin. At this point, you should have accomplished the following: - - * Backed up your important files - * Created Windows installation media - * Created Ubuntu installation media - - - -There are two ways of going about the installation. First, if you already have Windows 10 installed, you can have the Ubuntu installer resize the partition, and the installation will proceed in the empty space. Or, if you haven't installed Windows 10, install it on a smaller partition you can set up during the installation process. (I'll describe how to do that below.) The second way is preferred and less error-prone. There's a good chance you won't have any issues either way, but installing Windows manually and giving it a smaller partition, then installing Ubuntu, is the easiest way to go. - -If you already have Windows 10 on your computer, skip the following Windows installation instructions and proceed to Installing Ubuntu. - -#### Installing Windows - -Insert the Windows installation media you created into your computer and boot from it. How you do this depends on your computer, but most have a key you can press to initiate the boot menu. On a Dell PC for example, that key is F12. If the flash drive doesn't show up as an option, you may need to restart the computer. Sometimes it will show up only if you've inserted the media before turning on the computer. If you see a message like, "press any key to boot from the installation media," press a key. You should see the following screen. Select your language and keyboard style and click Next. - -![Windows setup][5] - -Click on Install now to start the Windows installer. - -On the next screen, it will ask for your product key. If you don't have one because Windows 10 came with your PC, select "I don't have a product key." It should automatically activate after the installation once it catches up with updates. If you do have a product key, type that in and click Next. - - -![Enter product key][7] - - -Select which version of Windows you want to install. If you have a retail copy, the label will tell you what version you have. Otherwise, it is typically located with the documentation that came with your computer. In most cases, it's going to be either Windows 10 Home or Windows 10 Pro. Most PCs that come with the Home edition have a label that simply reads "Windows 10," while Pro is clearly marked. - - -![Select Windows version][10] - - -Accept the license agreement by checking the box, then click Next. - - -![Accept license terms][12] - - -After accepting the agreement, you have two installation options available. Choose the second option, Custom: Install Windows only (advanced). - - -![Select type of Windows installation][14] - - -The next screen should show your current hard disk configuration. - - -![Hard drive configuration][16] - - -Your results will probably look different than mine. I have never used this hard disk before, so it's completely unallocated. You will probably see one or more partitions for your current operating system. Highlight each partition and remove it. - -At this point, your screen will show your entire disk as unallocated. To continue, create a new partition. - - -![Create a new partition][18] - - -Here you can see that I divided the drive in half (or close enough) by creating a partition of 81,920MB (which is close to half of 160GB). Give Windows at least 40GB, preferably 64GB or more. Leave the rest of the drive unallocated, as that's where you'll install Ubuntu later. - -Your results will look similar to this: - - -![Leaving a partition with unallocated space][20] - - -Confirm the partitioning looks good to you and click Next. Windows will begin installing. - - -![Installing Windows][22] - - -If your computer successfully boots into Windows, you're all set to move on to the next step. - -![Windows desktop][24] - - -#### Installing Ubuntu - -Whether it was already there or you worked through the steps above, at this point you should have Windows installed. Now use the Ubuntu installation media you created earlier to boot into Ubuntu. Go ahead and insert the media and boot your computer from it. Again, the exact sequence of keys to access the boot menu varies from one computer to another, so check your documentation if you're not sure. If all goes well, you see the following screen once the media finishes loading: - - -![Ubuntu installation welcome screen][26] - - -Here, you can select between Try Ubuntu or Install Ubuntu. Don't install just yet; instead, click Try Ubuntu. After it finishes loading, you should see the Ubuntu desktop. - - -![Ubuntu desktop][28] - -By clicking Try Ubuntu, you have opted to try out Ubuntu before you install it. Here, in Live mode, you can play around with Ubuntu and make sure everything works before you commit to the installation. Ubuntu works with most PC hardware, but it's always better to test it out beforehand. Make sure you can access the internet and get audio and video playback. Going to YouTube and playing a video is a good way of doing all of that at once. If you need to connect to a wireless network, click on the networking icon at the top-right of the screen. There, you can find a list of wireless networks and connect to yours. - -Once you're ready to go, double-click on the Install Ubuntu 18.04 LTS icon on the desktop to launch the installer. - -Choose the language you want to use for the installation process, then click Continue. - - -![Select language in Ubuntu][30] - - -Next, choose the keyboard layout. Once you've made your selection, click Continue. - - -![Select keyboard in Ubuntu][32] - -You have a few options on the screen below. One, you can choose a Normal or a Minimal installation. For most people, the Normal installation is ideal. Advanced users may want to do a Minimal install instead, which has fewer software applications installed by default. In addition, you can choose to download updates and whether or not to include third-party software and drivers. I recommend checking both of those boxes. When done, click Continue. - - -![Choose Ubuntu installation options][34] - -The next screen asks whether you want to erase the disk or set up a dual-boot. Since you're dual-booting, choose Install Ubuntu alongside Windows 10. Click Install Now. - - -![install Ubuntu alongside Windows][36] - - -The following screen may appear. If you installed Windows from scratch and left unallocated space on the disk, Ubuntu will automatically set itself up in the empty space, so you won't see this screen. If you already had Windows 10 installed and it's taking up the entire drive, this screen will appear and give you an option to select a disk at the top. If you have just one disk, you can choose how much space to steal from Windows and apply to Ubuntu. You can drag the vertical line in the middle left and right with your mouse to take space away from one and gives it to the other. Adjust this exactly the way you want it, then click Install Now. - - -![Allocate drive space][38] - - -You should see a confirmation screen indicating what Ubuntu plans on doing. If everything looks right, click Continue. - -Ubuntu is now installing in the background. You still have some configuration to do, though. While Ubuntu tries its best to figure out your location, you can click on the map to narrow it down to ensure your time zone and other things are set correctly. - -Next, fill in the user account information: your name, computer name, username, and password. Click Continue when you're done. - -There you have it! The installation is complete. Go ahead and reboot the PC. - -If all went according to plan, you should see a screen similar to this when your computer restarts. Choose Ubuntu or Windows 10; the other options are for troubleshooting, so I won't go into them. - -Try booting into both Ubuntu and Windows to test them out and make sure everything works as expected. If it does, you now have both Windows and Ubuntu installed on your computer. - --------------------------------------------------------------------------------- - -via: https://opensource.com/article/18/5/dual-boot-linux - -作者:[Jay LaCroix][a] -选题:[lujun9972](https://github.com/lujun9972) -译者:[译者ID](https://github.com/译者ID) -校对:[校对者ID](https://github.com/校对者ID) - -本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出 - -[a]:https://opensource.com/users/jlacroix -[1]:https://www.microsoft.com/en-us/software-download/windows10 -[2]:https://www.ubuntu.com/download/desktop -[3]:http://www.etcher.io -[4]:/file/397066 -[5]:https://opensource.com/sites/default/files/uploads/linux-dual-boot_01.png (Windows setup) -[6]:/file/397076 -[7]:https://opensource.com/sites/default/files/uploads/linux-dual-boot_03.png (Enter product key) -[8]:data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw== (Click and drag to move) -[9]:/file/397081 -[10]:https://opensource.com/sites/default/files/uploads/linux-dual-boot_04.png (Select Windows version) -[11]:/file/397086 -[12]:https://opensource.com/sites/default/files/uploads/linux-dual-boot_05.png (Accept license terms) -[13]:/file/397091 -[14]:https://opensource.com/sites/default/files/uploads/linux-dual-boot_06.png (Select type of Windows installation) -[15]:/file/397096 -[16]:https://opensource.com/sites/default/files/uploads/linux-dual-boot_07.png (Hard drive configuration) -[17]:/file/397101 -[18]:https://opensource.com/sites/default/files/uploads/linux-dual-boot_08.png (Create a new partition) -[19]:/file/397106 -[20]:https://opensource.com/sites/default/files/uploads/linux-dual-boot_09.png (Leaving a partition with unallocated space) -[21]:/file/397111 -[22]:https://opensource.com/sites/default/files/uploads/linux-dual-boot_10.png (Installing Windows) -[23]:/file/397116 -[24]:https://opensource.com/sites/default/files/uploads/linux-dual-boot_11.png (Windows desktop) -[25]:/file/397121 -[26]:https://opensource.com/sites/default/files/uploads/linux-dual-boot_12.png (Ubuntu installation welcome screen) -[27]:/file/397126 -[28]:https://opensource.com/sites/default/files/uploads/linux-dual-boot_13.png (Ubuntu desktop) -[29]:/file/397131 -[30]:https://opensource.com/sites/default/files/uploads/linux-dual-boot_15.png (Select language in Ubuntu) -[31]:/file/397136 -[32]:https://opensource.com/sites/default/files/uploads/linux-dual-boot_16.png (Select keyboard in Ubuntu) -[33]:/file/397141 -[34]:https://opensource.com/sites/default/files/uploads/linux-dual-boot_17.png (Choose Ubuntu installation options) -[35]:/file/397146 -[36]:https://opensource.com/sites/default/files/uploads/linux-dual-boot_18.png (Install Ubuntu alongside Windows) -[37]:/file/397151 -[38]:https://opensource.com/sites/default/files/uploads/linux-dual-boot_18b.png (Allocate drive space) From 90fa5f3eaf61ccbfa47a29dfe309f9cb6103302e Mon Sep 17 00:00:00 2001 From: Auk7F7 <34982730+Auk7F7@users.noreply.github.com> Date: Sat, 1 Dec 2018 16:52:41 +0800 Subject: [PATCH 12/12] Create 20180523 How to dual-boot Linux and Windows.md --- ...0523 How to dual-boot Linux and Windows.md | 238 ++++++++++++++++++ 1 file changed, 238 insertions(+) create mode 100644 translated/tech/20180523 How to dual-boot Linux and Windows.md diff --git a/translated/tech/20180523 How to dual-boot Linux and Windows.md b/translated/tech/20180523 How to dual-boot Linux and Windows.md new file mode 100644 index 0000000000..9047928ba6 --- /dev/null +++ b/translated/tech/20180523 How to dual-boot Linux and Windows.md @@ -0,0 +1,238 @@ +如何实现 Linux + Windows 双系统启动 +===== + +![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/migration_innovation_computer_software.png?itok=VCFLtd0q) + +尽管 Linux 是一个有着广泛的硬件和软件支持的操作系统,但事实上有时你仍需要使用 Windows,也许是因为有些不能在 Linux 下运行的重要软件。但幸运地是, 双启动 Windows 和 Linux 是很简单的—在这篇文章中我将会向你展示如何实现 Windows 10 + Ubuntu 18.04 双系统启动。 + +在你开始之前,确保你已经备份了你的电脑文件。 虽然设置双启动过程不是非常复杂,但意外有可能仍会发生。所以花一点时间来备份你的重要文件以防混沌理论发挥作用。除了备份你的文件之外,考虑制作一份备份镜像也是个不错的选择,虽然这不是必需的且会变成一个更高级的过程。 + +### 要求 + +为了开始,你将需要以下5项东西: + +#### 1\. 两个 USB 闪存盘(或者 DVD-Rs) + +我推荐用 USB 闪存盘来安装 Windows 和 Ubuntu,因为他们比 DVDs 更快。这通常是毋庸置疑的, 但是创建一个可启动的介质会抹除闪存盘上的一切东西。因此,确保闪存盘是空的或者其包含的文件是你不再需要的。 + +如果你的电脑不支持从 USB 启动,你可以创建 DVD 介质来代替。不幸的是, 因为没有两台电脑似乎有相同的 DVD 烧录软件,所以我无法引导这一过程。 然而,如果你的 DVD 烧录软件有从一个 ISO 镜像中烧录的选项,这个选项是你需要的。 + +#### 2\. 一份 Windows 10 许可证 + +如果你的电脑已经安装 Windows 10,那么许可证将会被安装到你的电脑中,所以你不需要担心在安装过程中输入它。如果你购买的是零售版,你应该拥有一个需要在安装过程中输入的产品密钥。 + +#### 3\. Windows 10介质创建工具 + +下载并运行 Windows 10 [介质创建工具][1]。一旦你运行这个工具,它将会引导你完成在一个 USB 或者 DVD-R 上创建 Windows 安装介质的所需步骤。注意: 即使你已经安装了 Windows 10 。总之创建一个可引导的介质是一个不错的主意,万一刚好系统出错了且需要你重新安装。 + +#### 4\. Ubuntu 18.04 安装介质 + +下载 [Ubuntu 18.04][2] ISO 镜像。 + +#### 5\. Etcher 软件(用于制作一个可引导 Ubuntu 的 USB 驱动器) +用于为任何 Linux 发型版本创建可启动的介质的工具,我推荐 [Etcher][3]。Etcher 可以在三大主流操作系统(Linux,MacOS,和 Windows)上运行且不会让你覆盖当前操作系统的分区。 + +一旦你下载完成并运行 Etcher,点击选择镜像并指向你在步骤4中下载的 Ubuntu ISO 镜像, 接下来, 点击驱动器以选择你的闪存驱动器,然后点击 ` Flash!` 开始将闪存驱动器转化为一个 Ubuntu 安装器的过程。 (如果你正使用一个 DVD-R, 使用你电脑中的 DVD 烧录软件来完成此过程。) + +### 安装 Windows 和 Ubuntu + +你应该准备好了,此时,你应该完成以下操作: + + * 备份你重要的文件 + * 创建 Windows 安装介质 + * 创建 Ubuntu 安装介质 + + + +有两种方法可以进行安装。首先,如果你已经安装了 WIndows 10 ,你可以让 Ubuntu 安装程序调整分区大小,然后在空白区域上进行安装。或者,如果你尚未安装 Windows 10,你可以在安装过程中将它安装在一个更小的分区上(下面我将描述如何去做)。第二种方法是首选的且出错率较低。很有可能你不会遇到任何问题。但是手动安装 Windows 并给它一个更小的分区,然后再安装 Ubuntu 是最简单的方法。 + +如果你的电脑上已经安装了 Windows 10,那么请跳过以下的 Windows 安装说明并继续安装 Ubuntu。 + +#### 安装 Windows + +将创建的 Windows 安装介质插入你的电脑中并引导其启动。这如何做取决于你的电脑。但大多数有一个可以按下以启动启动菜单的快捷键。例如,在戴尔的电脑上就是 F12键。如果闪存盘并未作为一个选项显示,那么你可能需要重新启动你的电脑。有时候,只有在启动电脑前插入介质才能使其显示出来。如果看到类似‘’请按任意键以从安装介质中启动“的信息,请按下任意一个键。然后你应该会看到如下的界面。选择你的语言和键盘样式,然后单击`Next`。 + + +![Windows 安装][5] + + +点击`现在安装`启动 Windows 安装程序 + +在下一个屏幕上,它会询问你的产品密钥。如果因你的电脑在出厂时已经安装了 Windows 10 而没有密钥的话,请选择‘’我没有一个产品密钥”。一旦赶上更新,它会在安装完成后自动激活。如果你有一个产品密钥,输入密钥并单击`下一步`。 + + +![输入产品密钥][7] + + +选择你想要安装的 Windows 版本。如果你有一个零售版,标签(LCTT 译者注:类似于 CPU 型号 的 logo 贴标,)会告诉你你有什么版本。否则,它通常与计算机的附带文档放在一起。在大多数情况下,它要么是 Windows 10 家庭版 或者 Windows 10 专业版。大多数带有 家庭版的电脑都有一个简单的标签,上面写着"Windows 10",而专业版则有明确的标签。 + + +![选择 Windows 版本][10] + + +勾选复选框以接受许可协议,然后单击`下一步`。 + + +![接受许可协议][12] + + +在接受协议后,你有两种可用的安装选项。选择第二个选项`自定义:只安装 Windows (高级)`。 + + +![选择 Windows 的安装方式][14] + + +接下来应该会显示你当前的硬盘配置。 + + +![硬盘配置][16] + + +你的结果可能看起来和我的不一样。我以前从来没有用过这个硬盘,所以它是完全未分配的。你可能会看到你当前操作系统的一个或多个分区。 + +此时,你的电脑屏幕将显示未分配的整个磁盘。创建一个新的分区以继续安装。 + + +![创建一个新分区][18] + + +你可以看到我通过创建一个81920MB 大小的分区(接近 160GB 的一半)将驱动器分成了一半(或者说分得足够近)。给 Windows 至少 40GB,最好 64GB 或者更多。把剩下的硬盘留着不要分配,作为以后安装 Ubuntu 的分区 + +你的结果应该看起来像这样: + + +![保留未分配空间的分区][20] + + +确认分区看起来很好,然后单击`下一步`。现在将开始安装 Windows。 + + +![安装 Windows][22] + + +如果你的电脑成功地引导进入了 Windows 桌面环境,你就可以进入下一步了。 + +![Windows 桌面][24] + + +#### 安装 Ubuntu + +无论你是已经安装了 Windows,还是完成了上面的步骤,现在你已经安装了 Windows。现在用你之前创建的 Ubuntu 安装介质来引导进入 Ubuntu。继续插入安装介质并从中引导你的电脑,同样,启动引导菜单的快捷键因计算机型号而异,因此如果你不确定,请查阅你的文档。如果一切顺利的话,当安装介质加载完成之后,你将会看到以下界面: + + +![Ubuntu 安装欢迎屏幕][26] + + +在这里,你可以选择 `尝试 Ubuntu` 或者 `安装 Ubuntu`。现在不要安装,相反,点击 `尝试 Ubuntu`。当完成加载之后,你应该可以看到 Ubuntu 桌面。 + +![Ubuntu 桌面][28] + +通过单击`尝试 Ubuntu`,你已经选择在安装之前试用 Ubuntu。 在 Live 模式下,你可以试用 Ubuntu,确保在你安装之前一切正常。Ubuntu 能兼容大多数 PC 硬件,但最好提前测试一下。确保你可以访问互联网并可以正常播放音频和视频。登录 YouTube 播放视频是一次性完成所有这些工作的好方法。如果你需要连接到无线网络,请单击屏幕右上角的网络图标。在那里,你可以找到一个无线网络列表并连接到你的无线网络。 + +准备好之后,双击桌面上的 `安装 Ubuntu 18.04 LTS`图标启动安装程序。 + +选择要用于安装过程的语言,然后单击 `继续`。 + + +![选择 Ubuntu 的语言][30] + + +接下来,选择键盘布局。完成后选择后,单击`继续`。 + + +![选择 Ubuntu 的键盘][32] + +在下面的屏幕上有一些选项。一,你可以选择一个正常安装或最小化安装。对大多数人来说,普通安装是理想的。高级用户可能想要默认安装应用程序比较少的最小化安装。此外,你还可以选择下载更新以及是否包含第三方软件和驱动程序。我建议同时检查这两个方框。完成后,单击`继续`。 + + +![选择 Ubuntu 安装选项][34] + +下一个屏幕将询问你是要擦除磁盘还是设置双启动。由于你是双启动,因此请选择`安装 Ubuntu,与 Windows 10共存`,单击`现在安装`。 + + +![安装 Ubuntu,与 Windows 10共存][36] + + +可能会出现以下屏幕。如果你从头开始安装 Windows 并在磁盘上保留了未分区的空间, Ubuntu 将会自动在空白区域中自行设置分区,因此你将看不到此屏幕。如果你已经安装了 Windows 10 并且它占用了整个驱动器,则会出现此屏幕,并在顶部为你提供一个选择磁盘的选项。如果你只有一个磁盘,则可以选择从 Windows 窃取多少空间给 Ubuntu。你可以使用鼠标左右拖动中间的垂直线以从其中一个分区中拿走一些空间并给另一个分区,按照你自己想要的方式调整它,然后单击`现在安装`。 + + +![分配驱动器空间][38] + + +你应该会看到一个显示 Ubuntu 计划将要做什么的确认屏幕,如果一切正常,请单击`继续`。 + +![确认屏幕][39] + +Ubuntu 正在后台安装。不过,你仍需要进行一些配置。当 Ubuntu 试图找到你的位置时,你可以点击地图来缩小范围以确保你的时区和其他设置是正确的。 + +![选择地理位置][40] + +接下来,填写用户账户信息:你的姓名、计算机名、用户名和密码。完成后单击`继续`。 + +![账户设置][41] + +现在你就拥有它了,安装完成了。继续并重启你的电脑。 + +![Ubuntu 安装完成][42] + +如果一切按计划进行,你应该会在计算机重新启动时看到类似的屏幕,选择 Ubuntu 或 Windows 10,其他选项是用于故障排除,所以我们一般不会选择进入其中。 + +![选择操作系统][43] + +尝试启动并进入 Ubuntu 或 Windows 以测试是否安装成功并确保一切按预期地正常工作。如果没有问题,你已经在你的电脑上安装了 Windows 和 Ubuntu 。 + +-------------------------------------------------------------------------------- + +via: https://opensource.com/article/18/5/dual-boot-linux + +作者:[Jay LaCroix][a] +选题:[lujun9972](https://github.com/lujun9972) +译者:[Auk7F7](https://github.com/Auk7F7) +校对:[校对者ID](https://github.com/校对者ID) + +本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出 + +[a]:https://opensource.com/users/jlacroix +[1]:https://www.microsoft.com/en-us/software-download/windows10 +[2]:https://www.ubuntu.com/download/desktop +[3]:http://www.etcher.io +[4]:/file/397066 +[5]:https://opensource.com/sites/default/files/uploads/linux-dual-boot_01.png "Windows setup" +[6]:/file/397076 +[7]:https://opensource.com/sites/default/files/uploads/linux-dual-boot_03.png "Enter product key" +[8]:data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw== "Click and drag to move" +[9]:/file/397081 +[10]:https://opensource.com/sites/default/files/uploads/linux-dual-boot_04.png "Select Windows version" +[11]:/file/397086 +[12]:https://opensource.com/sites/default/files/uploads/linux-dual-boot_05.png "Accept license terms" +[13]:/file/397091 +[14]:https://opensource.com/sites/default/files/uploads/linux-dual-boot_06.png "Select type of Windows installation" +[15]:/file/397096 +[16]:https://opensource.com/sites/default/files/uploads/linux-dual-boot_07.png "Hard drive configuration" +[17]:/file/397101 +[18]:https://opensource.com/sites/default/files/uploads/linux-dual-boot_08.png "Create a new partition" +[19]:/file/397106 +[20]:https://opensource.com/sites/default/files/uploads/linux-dual-boot_09.png "Leaving a partition with unallocated space" +[21]:/file/397111 +[22]:https://opensource.com/sites/default/files/uploads/linux-dual-boot_10.png "Installing Windows" +[23]:/file/397116 +[24]:https://opensource.com/sites/default/files/uploads/linux-dual-boot_11.png "Windows desktop" +[25]:/file/397121 +[26]:https://opensource.com/sites/default/files/uploads/linux-dual-boot_12.png "Ubuntu installation welcome screen" +[27]:/file/397126 +[28]:https://opensource.com/sites/default/files/uploads/linux-dual-boot_13.png "Ubuntu desktop" +[29]:/file/397131 +[30]:https://opensource.com/sites/default/files/uploads/linux-dual-boot_15.png "Select language in Ubuntu" +[31]:/file/397136 +[32]:https://opensource.com/sites/default/files/uploads/linux-dual-boot_16.png "Select keyboard in Ubuntu" +[33]:/file/397141 +[34]:https://opensource.com/sites/default/files/uploads/linux-dual-boot_17.png "Choose Ubuntu installation options" +[35]:/file/397146 +[36]:https://opensource.com/sites/default/files/uploads/linux-dual-boot_18.png "Install Ubuntu alongside Windows" +[37]:/file/397151 +[38]:https://opensource.com/sites/default/files/uploads/linux-dual-boot_18b.png "Allocate drive space" +[39]:https://opensource.com/sites/default/files/uploads/linux-dual-boot_19.png "Confirmation screen" +[40]:https://opensource.com/sites/default/files/uploads/linux-dual-boot_20.png "Select location" +[41]:https://opensource.com/sites/default/files/uploads/linux-dual-boot_21.png "Account setup" +[42]:https://opensource.com/sites/default/files/uploads/linux-dual-boot_22.png "Installation complete" +[43]:https://opensource.com/sites/default/files/uploads/linux-dual-boot_23.png "Chose which OS to use"